summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSangjung Woo <sangjung.woo@samsung.com>2015-06-09 11:11:50 +0900
committerSangjung Woo <sangjung.woo@samsung.com>2015-06-09 15:10:34 +0900
commit625b8675d47177c383d19413ba1e12454a847864 (patch)
tree5d8f050818f580e3edc9c48de11f5bbb6508f30f
parent315e4e002c6c8cf9398c5d0625a4fac0e40830db (diff)
downloadresourced-tizen_3.0.2015.q2_common.tar.gz
resourced-tizen_3.0.2015.q2_common.tar.bz2
resourced-tizen_3.0.2015.q2_common.zip
* Rebase work until 'memory: disabled swap and vmpressure modules for mobile profile (c4e54093)' * Support runtime-info API * Fix the minor bugs & turn up each module * Support aarch64, arm32 and emulator Change-Id: I8dfc1d1d3aa9bcdd89f7632752d968fe3a854484 Signed-off-by: Sangjung Woo <sangjung.woo@samsung.com>
-rw-r--r--CMakeLists.txt20
-rw-r--r--CMakeLists/resourced.txt56
-rw-r--r--data/traffic_db.sql30
-rw-r--r--docs/func.txt4
-rwxr-xr-xinclude/data_usage.h13
-rwxr-xr-xinclude/rd-network.h936
-rw-r--r--packaging/resourced-logging.service11
-rw-r--r--packaging/resourced.service1
-rw-r--r--packaging/resourced.spec112
-rw-r--r--packaging/resourced_swapoff.service2
-rw-r--r--resourced.manifest16
-rw-r--r--resourced.pc.in16
-rw-r--r--resourced.rule12
-rw-r--r--resourced_nodb.manifest29
-rw-r--r--src/common/appid-helper.c18
-rw-r--r--src/common/cgroup.c40
-rw-r--r--src/common/cgroup.h19
-rw-r--r--src/common/const.h10
-rw-r--r--src/common/daemon-options.h1
-rw-r--r--src/common/edbus-handler.c52
-rw-r--r--src/common/edbus-handler.h14
-rw-r--r--src/common/macro.h22
-rw-r--r--src/common/module-data.c1
-rw-r--r--src/common/module-data.h1
-rw-r--r--src/common/module.c13
-rw-r--r--src/common/module.h3
-rw-r--r--src/common/notifier.h5
-rw-r--r--src/common/swap-common.h20
-rw-r--r--src/common/trace.h4
-rw-r--r--src/cpu/cpu.c164
-rw-r--r--src/cpu/cpu.conf6
-rw-r--r--src/cpu/logging-cpu.c13
-rw-r--r--src/logging/include/logging.h1
-rw-r--r--src/logging/logging.c73
-rw-r--r--src/memory/helper.c542
-rw-r--r--src/memory/helper.h58
-rw-r--r--src/memory/logging-memory.c201
-rw-r--r--src/memory/lowmem-dbus.c17
-rw-r--r--src/memory/lowmem-handler.c874
-rw-r--r--src/memory/lowmem-handler.h23
-rw-r--r--src/memory/memcontrol.c146
-rw-r--r--src/memory/memcontrol.h77
-rw-r--r--src/memory/memory_eng.conf39
-rw-r--r--src/memory/memory_user.conf33
-rw-r--r--src/memory/vmpressure-lowmem-handler.c1248
-rw-r--r--src/memps/CMakeLists.txt4
-rw-r--r--src/memps/memps.c6
-rw-r--r--src/network/500.resourced-datausage.patch.sh19
-rwxr-xr-xsrc/network/CMakeLists.txt90
-rw-r--r--src/network/app-stat.c235
-rw-r--r--src/network/counter-process.c422
-rw-r--r--src/network/counter.c1
-rw-r--r--src/network/datausage-common.c734
-rw-r--r--src/network/datausage-quota-processing.c681
-rw-r--r--src/network/datausage-quota.c24
-rw-r--r--src/network/datausage-vconf-callbacks.c17
-rw-r--r--src/network/datausage-vconf-common.c10
-rw-r--r--src/network/db-guard.c118
-rw-r--r--src/network/foreach.c103
-rw-r--r--src/network/generic-netlink.c107
-rw-r--r--src/network/iface-cb.c1
-rw-r--r--src/network/iface.c152
-rw-r--r--src/network/include/app-stat.h (renamed from src/common/app-stat.h)39
-rw-r--r--src/network/include/counter.h12
-rw-r--r--src/network/include/datausage-common.h25
-rw-r--r--src/network/include/datausage-quota-processing.h49
-rw-r--r--src/network/include/datausage-restriction.h19
-rw-r--r--src/network/include/datausage-vconf-common.h1
-rw-r--r--src/network/include/db-guard.h (renamed from src/network/include/roaming.h)26
-rw-r--r--src/network/include/iface.h14
-rw-r--r--src/network/include/net-cls-cgroup.h16
-rw-r--r--src/network/include/netlink-restriction.h6
-rw-r--r--src/network/include/nfacct-rule.h28
-rw-r--r--src/network/include/nl-helper.h2
-rw-r--r--src/network/include/notification.h29
-rw-r--r--src/network/include/protocol-info.h42
-rw-r--r--src/network/include/restriction-handler.h8
-rw-r--r--src/network/include/storage.h3
-rw-r--r--src/network/include/telephony.h49
-rw-r--r--src/network/include/tethering-restriction.h1
-rw-r--r--src/network/join-dummy.c (renamed from src/network/dummy_roaming.c)27
-rw-r--r--src/network/ktgrabber-parser.c110
-rw-r--r--src/network/ktgrabber-restriction.c5
-rw-r--r--src/network/main.c7
-rw-r--r--src/network/net-cls-cgroup.c88
-rw-r--r--src/network/network-dummy.c150
-rw-r--r--src/network/network.c162
-rw-r--r--src/network/nf-restriction.c28
-rw-r--r--src/network/nfacct-rule.c297
-rw-r--r--src/network/notification-mobile.c204
-rw-r--r--src/network/notification-wearable.c (renamed from src/network/notification.c)37
-rw-r--r--src/network/protocol-info.c109
-rw-r--r--src/network/reset.c33
-rw-r--r--src/network/restriction-handler.c89
-rw-r--r--src/network/restriction-helper.c5
-rw-r--r--src/network/restriction-local.c202
-rw-r--r--src/network/restriction.c2
-rw-r--r--src/network/roaming.c89
-rw-r--r--src/network/specific-trace.c8
-rw-r--r--src/network/storage.c84
-rw-r--r--src/network/telephony.c625
-rw-r--r--src/network/tethering-restriction.c11
-rwxr-xr-xsrc/network/update.c1
-rw-r--r--src/proc-stat/CMakeLists.txt7
-rw-r--r--src/proc-stat/include/proc-main.h31
-rw-r--r--src/proc-stat/include/proc-process.h3
-rw-r--r--src/proc-stat/include/proc-usage-stats-helper.h85
-rw-r--r--src/proc-stat/include/proc-usage-stats.h33
-rw-r--r--src/proc-stat/proc-main.c364
-rw-r--r--src/proc-stat/proc-monitor.c79
-rw-r--r--src/proc-stat/proc-process.c225
-rw-r--r--src/proc-stat/proc-usage-stats-helper.c256
-rw-r--r--src/proc-stat/proc-usage-stats.c378
-rw-r--r--src/resourced/init.c24
-rw-r--r--src/resourced/init.h3
-rw-r--r--src/swap/swap.c589
-rw-r--r--src/swap/swap.conf5
-rw-r--r--src/utils/datausage-tool.c78
118 files changed, 7565 insertions, 5057 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3496ac83..88f5914c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,14 +39,9 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX})
#following section is needed for pkg-config *.in file
SET(INCLUDEDIR ${PREFIX}/include)
SET(PC_NAME lib${RESOURCED})
-SET(PC_NAME_DEPRECATED ${fw_name})
-SET(PC_REQUIRED "glib-2.0 vconf vconf-internal-keys sqlite3 dlog edbus eina")
+SET(PC_REQUIRED "glib-2.0 vconf vconf-internal-keys sqlite3 dlog eina edbus")
-SET(PC_PROVIDED_LIBS "-l${PROC-STAT}")
-
-IF("${NETWORK_MODULE}" STREQUAL "ON")
- SET(PC_PROVIDED_LIBS "${PC_PROVIDED_LIBS} -l${NETWORK} -l${RESOURCED}")
-ENDIF()
+SET(PC_PROVIDED_LIBS "-l${PROC-STAT} -l${RESOURCED}")
IF("${POWERTOP_MODULE}" STREQUAL "ON")
SET(PC_PROVIDED_LIBS "${PC_PROVIDED_LIBS} -l${POWERTOP-WRAPPER}" )
@@ -61,16 +56,11 @@ CONFIGURE_FILE(
@ONLY
)
-CONFIGURE_FILE(
- ${fw_name}.pc.in
- ${CMAKE_SOURCE_DIR}/${fw_name}.pc
- @ONLY
-)
-
#init variables with sources
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_MEMORY_DIR ${CMAKE_SOURCE_DIR}/src/memory)
SET(INCLUDE_PUBLIC_DIR ${CMAKE_SOURCE_DIR}/include)
SET(RESOURCED_INCLUDEDIR ${INCLUDE_COMMON_DIR} ${INCLUDE_PUBLIC_DIR})
@@ -93,8 +83,8 @@ SET(VIP_SOURCE_DIR ${SOURCE_DIR}/vip-agent)
SET(TIMER_SOURCE_DIR ${SOURCE_DIR}/timer-slack)
INSTALL(FILES ${CMAKE_SOURCE_DIR}/lib${RESOURCED}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
INSTALL(FILES ${CMAKE_SOURCE_DIR}/resourced.conf DESTINATION /etc/dbus-1/system.d)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/resourced.rule DESTINATION /etc/smack/accesses2.d)
FILE(MAKE_DIRECTORY ${RESOURCED}-cmake)
CONFIGURE_FILE(${CMAKELISTS_DIR}/${RESOURCED}.txt ${RESOURCED}-cmake/CMakeLists.txt COPYONLY)
@@ -106,6 +96,4 @@ IF("${POWERTOP_MODULE}" STREQUAL "ON")
ADD_SUBDIRECTORY(${POWERTOP-WRAPPER_SOURCE_DIR})
ENDIF()
ADD_SUBDIRECTORY(${MEMPS_SOURCE_DIR})
-IF("${NETWORK_MODULE}" STREQUAL "ON")
ADD_SUBDIRECTORY(${NETWORK_SOURCE_DIR})
-ENDIF()
diff --git a/CMakeLists/resourced.txt b/CMakeLists/resourced.txt
index 2d45126a..92a7ecba 100644
--- a/CMakeLists/resourced.txt
+++ b/CMakeLists/resourced.txt
@@ -27,6 +27,7 @@ SET (HEADERS
${INCLUDE_COMMON_DIR}/module-data.h
${INCLUDE_COMMON_DIR}/module.h
${INCLUDE_COMMON_DIR}/swap-common.h
+ ${INCLUDE_MEMORY_DIR}/helper.h
)
SET (SOURCES
@@ -38,20 +39,24 @@ SET (SOURCES
${COMMON_SOURCE_DIR}/file-helper.c
${COMMON_SOURCE_DIR}/module-data.c
${COMMON_SOURCE_DIR}/module.c
- ${NETWORK_SOURCE_DIR}/counter.c
${PROC-STAT_SOURCE_DIR}/proc-handler.c
${PROC-STAT_SOURCE_DIR}/proc-main.c
${PROC-STAT_SOURCE_DIR}/proc-noti.c
${PROC-STAT_SOURCE_DIR}/proc-process.c
${PROC-STAT_SOURCE_DIR}/proc-monitor.c
+ ${PROC-STAT_SOURCE_DIR}/proc-usage-stats.c
+ ${PROC-STAT_SOURCE_DIR}/proc-usage-stats-helper.c
${RESOURCED_SOURCE_DIR}/init.c
${RESOURCED_SOURCE_DIR}/main.c
+ ${MEMORY_SOURCE_DIR}/helper.c
)
INSTALL(FILES ${DATA_DIR}/${EXCLUDE_LIST_FILE_NAME} DESTINATION /usr/etc)
#network module
IF("${NETWORK_MODULE}" STREQUAL "ON")
-
+ SET(SOURCES ${SOURCES}
+ ${NETWORK_SOURCE_DIR}/counter.c
+ )
IF("${DATAUSAGE_TYPE}" STREQUAL "NFACCT")
SET(CONFIG_DATAUSAGE_NFACCT 1)
SET(SOURCES ${SOURCES}
@@ -62,6 +67,17 @@ IF("${NETWORK_MODULE}" STREQUAL "ON")
SET(SOURCES ${SOURCES}
${NETWORK_SOURCE_DIR}/generic-netlink.c
${NETWORK_SOURCE_DIR}/ktgrabber-restriction.c
+ ${NETWORK_SOURCE_DIR}/ktgrabber-parser.c
+ )
+ ENDIF()
+
+ IF("${WEARABLE_NOTI}" STREQUAL "ON")
+ SET(SOURCES ${SOURCES}
+ ${NETWORK_SOURCE_DIR}/notification-wearable.c
+ )
+ ELSE()
+ SET(SOURCES ${SOURCES}
+ ${NETWORK_SOURCE_DIR}/notification-mobile.c
)
ENDIF()
@@ -75,20 +91,25 @@ IF("${NETWORK_MODULE}" STREQUAL "ON")
${NETWORK_SOURCE_DIR}/datausage-common.c
${NETWORK_SOURCE_DIR}/iface-cb.c
${NETWORK_SOURCE_DIR}/nl-helper.c
- ${NETWORK_SOURCE_DIR}/notification.c
${NETWORK_SOURCE_DIR}/restriction-handler.c
${NETWORK_SOURCE_DIR}/restriction-helper.c
${NETWORK_SOURCE_DIR}/restriction-local.c
${NETWORK_SOURCE_DIR}/tethering-restriction.c
+ ${NETWORK_SOURCE_DIR}/db-guard.c
)
- IF ("${TETHERING_FEATURE}" STREQUAL "ON")
- SET(TETHERING_FEATURE 1)
- ENDIF()
-
INSTALL(FILES ${NETWORK_SOURCE_DIR}/network.conf
DESTINATION /etc/resourced)
+ INSTALL(FILES ${NETWORK_SOURCE_DIR}/500.resourced-datausage.patch.sh
+ DESTINATION /etc/opt/upgrade)
+
+ SET (REQUIRES_LIST ${REQUIRES_LIST}
+ openssl
+ tapi
+ )
+
+
ENDIF()
IF("${VIP_AGENT}" STREQUAL "ON")
@@ -121,15 +142,12 @@ ENDIF()
IF("${MEMORY_MODULE}" STREQUAL "ON")
SET(SOURCES ${SOURCES}
${MEMORY_SOURCE_DIR}/lowmem-dbus.c
+ ${MEMORY_SOURCE_DIR}/memcontrol.c
)
- IF("${MEMORY_CGROUP}" STREQUAL "ON")
- SET(SOURCES ${SOURCES}
- ${MEMORY_SOURCE_DIR}/vmpressure-lowmem-handler.c
- )
+ IF("${MEMORY_VMPRESSURE}" STREQUAL "ON")
+ SET(SOURCES ${SOURCES} ${MEMORY_SOURCE_DIR}/vmpressure-lowmem-handler.c)
ELSE()
- SET(SOURCES ${SOURCES}
- ${MEMORY_SOURCE_DIR}/lowmem-handler.c
- )
+ SET(SOURCES ${SOURCES} ${MEMORY_SOURCE_DIR}/lowmem-handler.c)
ENDIF()
ADD_DEFINITIONS("-DMEMORY_SUPPORT")
ENDIF()
@@ -162,9 +180,10 @@ SET (REQUIRES_LIST ${REQUIRES_LIST}
vconf
vconf-internal-keys
ecore-file
+ eina
edbus
+ bundle
libsystemd-daemon
- eina
)
IF("${LOGGING_MODULE}" STREQUAL "ON")
@@ -180,7 +199,7 @@ FOREACH(flag ${daemon_pkgs_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag} -pthread")
ENDFOREACH(flag)
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE")
CONFIGURE_FILE(${INCLUDE_COMMON_DIR}/config.h.in
${INCLUDE_COMMON_DIR}/config.h)
@@ -198,7 +217,7 @@ TARGET_LINK_LIBRARIES(cgroup-test ${daemon_pkgs_LDFLAGS} "-L/lib/ -lrt")
ADD_EXECUTABLE (${PROJECT_NAME} ${HEADERS} ${SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_NAME}
- ${daemon_pkgs_LDFLAGS}
+ ${daemon_pkgs_LDFLAGS} "-pie -lrt"
)
IF("${NETWORK_MODULE}" STREQUAL "ON")
@@ -208,7 +227,7 @@ IF("${NETWORK_MODULE}" STREQUAL "ON")
storage
settings
net-cls
- roaming
+ telephony
net-iface
)
@@ -241,6 +260,7 @@ ENDIF()
IF("${SWAP_MODULE}" STREQUAL "ON")
INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/scripts/resourced-zram.sh DESTINATION bin)
+ INSTALL(FILES ${SWAP_SOURCE_DIR}/swap.conf DESTINATION /etc/resourced)
ENDIF()
IF("${CPU_MODULE}" STREQUAL "ON")
diff --git a/data/traffic_db.sql b/data/traffic_db.sql
index 628e6695..fec882b5 100644
--- a/data/traffic_db.sql
+++ b/data/traffic_db.sql
@@ -9,10 +9,13 @@ CREATE TABLE IF NOT EXISTS statistics (
is_roaming INT,
hw_net_protocol_type INT,
ifname TEXT,
- PRIMARY KEY (binpath, time_stamp, iftype)
+ reserved TEXT,
+ imsi TEXT,
+ ground INT,
+ PRIMARY KEY (binpath, time_stamp, iftype, imsi)
);
-CREATE INDEX IF NOT EXISTS binpath_st_idx ON statistics(binpath, iftype);
+CREATE INDEX IF NOT EXISTS binpath_st_idx ON statistics(binpath, iftype, imsi);
CREATE TABLE IF NOT EXISTS quotas (
binpath TEXT,
@@ -24,10 +27,13 @@ CREATE TABLE IF NOT EXISTS quotas (
start_time BIGINT,
iftype INT,
roaming INT,
- PRIMARY KEY(binpath, iftype, roaming)
+ reserved TEXT,
+ imsi TEXT,
+ ground INT,
+ PRIMARY KEY(binpath, iftype, roaming, imsi, ground)
);
-CREATE INDEX IF NOT EXISTS binpath_qt_idx ON quotas(binpath, iftype);
+CREATE INDEX IF NOT EXISTS binpath_qt_idx ON quotas(binpath, iftype, imsi);
CREATE TABLE IF NOT EXISTS effective_quotas (
binpath TEXT,
@@ -38,10 +44,12 @@ CREATE TABLE IF NOT EXISTS effective_quotas (
iftype INT,
roaming INT,
state INT DEFAULT 0,
- PRIMARY KEY (binpath, iftype, start_time, finish_time, roaming)
+ reserved TEXT,
+ imsi TEXT,
+ PRIMARY KEY (binpath, iftype, start_time, finish_time, roaming, imsi)
);
-CREATE INDEX IF NOT EXISTS binpath_effective_quotas_idx ON effective_quotas(binpath, iftype);
+CREATE INDEX IF NOT EXISTS binpath_effective_quotas_idx ON effective_quotas(binpath, iftype, imsi);
CREATE TABLE IF NOT EXISTS restrictions (
binpath TEXT,
@@ -51,16 +59,20 @@ CREATE TABLE IF NOT EXISTS restrictions (
rst_state INT,
quota_id INT,
roaming INT,
- PRIMARY KEY (binpath, iftype)
+ reserved TEXT,
+ ifname TEXT,
+ PRIMARY KEY (binpath, iftype, ifname, quota_id)
);
-CREATE INDEX IF NOT EXISTS binpath_restrictions_idx ON restrictions(binpath, iftype);
+CREATE INDEX IF NOT EXISTS binpath_restrictions_idx ON restrictions(binpath, iftype, ifname);
CREATE TABLE IF NOT EXISTS iface_status (
update_time BIGINT,
iftype INT,
ifstatus INT,
- PRIMARY KEY (update_time)
+ reserved TEXT,
+ ifname TEXT,
+ PRIMARY KEY (update_time, iftype, ifstatus)
);
CREATE INDEX IF NOT EXISTS update_tm_if_idx ON iface_status(update_time, iftype, ifstatus);
diff --git a/docs/func.txt b/docs/func.txt
index b1ce4046..1c76d93a 100644
--- a/docs/func.txt
+++ b/docs/func.txt
@@ -272,9 +272,9 @@ int datausage_quota_init(sqlite3 *db)
Initializes queries used in data usage quota functions.
--------------------------------------------------------------------------------
-u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create)
+u_int32_t get_classid_by_app_id(const char *pkg_name, int create)
-Converts application package name to network class.
+Converts application id to network class.
pkg_name - zero-terminated string containing the package name
create - if non-zero attempts to create the cgroup for pkg_name before fetching network class ID
diff --git a/include/data_usage.h b/include/data_usage.h
index e9bc2152..6429f06a 100755
--- a/include/data_usage.h
+++ b/include/data_usage.h
@@ -121,6 +121,7 @@ typedef struct {
int snd_warning_limit;
int rcv_warning_limit;
resourced_roaming_type roaming;
+ char *ifname;
} resourced_net_restrictions;
/**
@@ -199,10 +200,11 @@ typedef struct {
int64_t rcv_quota;
int snd_warning_threshold;
int rcv_warning_threshold;
- resourced_state_t quota_type;
+ resourced_state_t quota_type; /* TODO rename to ground */
resourced_iface_type iftype;
time_t *start_time;
resourced_roaming_type roaming_type;
+ const char *imsi;
} data_usage_quota;
/**
@@ -218,8 +220,10 @@ typedef struct {
*/
struct datausage_quota_reset_rule {
const char *app_id;
+ const char *imsi;
resourced_iface_type iftype;
resourced_roaming_type roaming;
+ resourced_state_t quota_type;
};
/**
@@ -247,12 +251,13 @@ typedef struct {
typedef struct {
const char *app_id;
const char *ifname;
+ const char *imsi;
resourced_iface_type iftype;
resourced_tm_interval *interval;
- resourced_common_info foreground;
- resourced_common_info background;
+ resourced_counters cnt;
resourced_roaming_type roaming;
resourced_hw_net_protocol_type hw_net_protocol_type;
+ resourced_state_t ground;
} data_usage_info;
/**
@@ -298,6 +303,7 @@ typedef struct {
*/
typedef struct {
const char *app_id;
+ const char *ifname;
resourced_iface_type iftype;
resourced_restriction_state rst_state;
int rcv_limit;
@@ -328,6 +334,7 @@ typedef resourced_cb_ret(*resourced_restriction_cb)(
typedef struct {
unsigned char version;
char *app_id;
+ const char *imsi;
resourced_iface_type iftype;
resourced_tm_interval *interval;
resourced_connection_period_type connection_state;
diff --git a/include/rd-network.h b/include/rd-network.h
deleted file mode 100755
index 4ebb2816..00000000
--- a/include/rd-network.h
+++ /dev/null
@@ -1,936 +0,0 @@
-/*
- * Copyright (c) 2011 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 __RD_NETWORK_H__
-#define __RD_NETWORK_H__
-
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Enumeration for return type
- */
-typedef enum {
- NETWORK_ERROR_NONMONITOR = -9, /** < Process don't show watchdog popup */
- NETWORK_ERROR_NOTIMPL = -7, /**< Not implemented yet error */
- NETWORK_ERROR_UNINITIALIZED = -6, /**< Cgroup doen't mounted or daemon not started */
- NETWORK_ERROR_NO_DATA = -5, /**< Success, but no data */
- NETWORK_ERROR_INVALID_PARAMETER = -4,/**< Invalid parameter */
- NETWORK_ERROR_OUT_OF_MEMORY = -3, /**< Out of memory */
- NETWORK_ERROR_DB_FAILED = -2, /**< Database error */
- NETWORK_ERROR_FAIL = -1, /**< General error */
- NETWORK_ERROR_NONE = 0 /**< General success */
-} network_error_e;
-
-
-/**
- * @brief Enumeration for return type of the callback
- */
-typedef enum {
- NETWORK_CANCEL = 0, /**< cancel */
- NETWORK_CONTINUE = 1, /**< continue */
-} network_cb_ret_e;
-
-/**
- * @brief Enumeration for the monitored process state
- */
-typedef enum {
- NETWORK_STATE_UNKNOWN = 0,
- NETWORK_STATE_FOREGROUND = 1 << 1, /** < foreground state */
- NETWORK_STATE_BACKGROUND = 1 << 2, /** < background state */
- NETWORK_STATE_LAST_ELEM = 1 << 3
-} network_state_e;
-
-/**
- * @brief Enumeration for network restriction state
- */
-typedef enum {
- NETWORK_RESTRICTION_UNDEFINDED,
- NETWORK_RESTRICTION_ACTIVATED, /** < restriction activated - means it
- was sent to kernel */
- NETWORK_RESTRICTION_EXCLUDED, /** < restriction has been excluded -
- means it was sent to kernel as
- excluded */
- NETWORK_RESTRICTION_REMOVED, /** < restriction has been removed */
-
- NETWORK_RESTRICTION_MAX_VALUE
-} network_restriction_state;
-
-/**
- * @brief Enumeration for network interface types
- */
-typedef enum {
- NETWORK_IFACE_UNKNOWN, /**< undefined iface */
- NETWORK_IFACE_DATACALL, /**< mobile data */
- NETWORK_IFACE_WIFI, /**< wifi data */
- NETWORK_IFACE_WIRED, /**< wired interface */
- NETWORK_IFACE_BLUETOOTH, /**< bluetooth interface */
- NETWORK_IFACE_ALL, /**< enumerate all network interface types */
- NETWORK_IFACE_LAST_ELEM
-} network_iface_e;
-
-/**
- * @brief Structure for time interval
- * @details It's time interval. Zero interval since 0 til 0 means entires interval.
- */
-typedef struct {
- time_t from;
- time_t to;
-} network_tm_interval_s;
-
-/**
- * @brief Enumeration for network connection period type
- * @details Last received/sent mean counting data from the first connection of each interface
- */
-typedef enum {
- NETWORK_CON_PERIOD_UNKNOWN, /**< Undefined period */
- NETWORK_CON_PERIOD_LAST_RECEIVED_DATA, /**< Last received data */
- NETWORK_CON_PERIOD_LAST_SENT_DATA, /**< Last sent data */
- NETWORK_CON_PERIOD_TOTAL_RECEIVED_DATA, /**< Total received data */
- NETWORK_CON_PERIOD_TOTAL_SENT_DATA, /**< Total sent data */
- NETWORK_CON_PERIOD_LAST_ELEM
-} network_connection_period_e;
-
-/**
- * @brief Enumeration for network roaming type
- */
-typedef enum {
- NETWORK_ROAMING_UNKNOWN, /**< can't define roaming - roaming unknown */
- NETWORK_ROAMING_ENABLE, /**< in roaming */
- NETWORK_ROAMING_DISABLE, /**< not in roaming */
- NETWORK_ROAMING_LAST_ELEM,
-} network_roaming_e;
-
-/**
- * @brief Enumeration for hardware network protocol types
- */
-typedef enum {
- NETWORK_PROTOCOL_NONE, /**< Network unknown */
- NETWORK_PROTOCOL_DATACALL_NOSVC, /**< Network no service */
- NETWORK_PROTOCOL_DATACALL_EMERGENCY, /**< Network emergency */
- NETWORK_PROTOCOL_DATACALL_SEARCH, /**< Network search 1900 */
- NETWORK_PROTOCOL_DATACALL_2G, /**< Network 2G */
- NETWORK_PROTOCOL_DATACALL_2_5G, /**< Network 2.5G */
- NETWORK_PROTOCOL_DATACALL_2_5G_EDGE, /**< Network EDGE */
- NETWORK_PROTOCOL_DATACALL_3G, /**< Network UMTS */
- NETWORK_PROTOCOL_DATACALL_HSDPA, /**< Network HSDPA */
- NETWORK_PROTOCOL_DATACALL_LTE, /**< Network LTE */
- NETWORK_PROTOCOL_MAX_ELEM
-} network_hw_net_protocol_e;
-
-/**
- * @brief Enumeration for the boolean option
- * @details Description of the boolean option for enabling/disabling
- * network interfaces and enabling/disabling some behaviar
- */
-typedef enum {
- NETWORK_OPTION_UNDEF,
- NETWORK_OPTION_ENABLE,
- NETWORK_OPTION_DISABLE
-} network_option_e;
-
-/**
- * @brief Structure for network option
- * @details Set of the options.
- * version - contains structure version
- * wifi - enable/disable wifi, NETWORK_OPTION_UNDEF to leave option as is
- * datacall - enable/disable datacall, NETWORK_OPTION_UNDEF to leave option as is
- * network_timer - set period of the updating data from the kernel,
- * 0 to leave option as is
- * datacall_logging - enable/disable datacall_logging,
- * NETWORK_OPTION_UNDEF to leave option as is
- */
-typedef struct {
- unsigned char version;
- network_option_e wifi;
- network_option_e datacall;
- time_t network_timer;
- network_option_e datacall_logging;
-} network_option_s;
-
-/**
- * @brief Set options, daemon will handle option setting.
- * @param[in] options The network state option
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_option_s
- * @see #network_get_option
- */
-network_error_e network_set_option(const network_option_s *options);
-
-/**
- * @brief Get performance control options.
- * @param[out] options The network state option
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_option_s
- * @see #network_set_option
- */
-network_error_e network_get_option(network_option_s *options);
-
-/**
- * @brief Make cgroup and put in it the given pid and generated classid
- * @details If cgroup already exists function just put pid in it.
- * @param[in] pid Process, that will be added to cgroup pkg name
- * @param[in] pkg_name Package name
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_get_classid_by_pkg_name
- */
-network_error_e network_make_cgroup_with_pid(const int pid,
- const char *pkg_name);
-
-/**
- * @brief Get classid from cgroup with name pkg_name
- * @param[in] pkg_name Name of the cgroup
- * @param[in] create In case of true - create cgroup if it's not exists
- * @return a positive value is classid, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_make_cgroup_with_pid
- */
-u_int32_t network_get_classid_by_pkg_name(const char *pkg_name, int create);
-
-/**
- * @brief Structure for network restriction information
- * @details
- * rs_type: foreground or background process
- * iftype - interface type to apply restriction
- * send_limit - amount number of engress bytes allowed for restriction
- * rcv_limit - amount number of ingress bytes allowed for restriction
- * old behaviour for send_limit & rcv_limit was 0
- * snd_warning_limit - threshold for warning notification on engress bytes
- * rcv_warning_limit - threshold for warning notification on ingress bytes
- * value - WARNING_THRESHOLD_UNDEF means no threshold
- * this limit is different from quota warning threshold,
- * threshold means remaining, limit means occupaied
- */
-typedef struct {
- network_state_e rs_type;
- network_iface_e iftype;
- int send_limit;
- int rcv_limit;
- int snd_warning_limit;
- int rcv_warning_limit;
-} network_restriction_s;
-
-/**
- * @brief Enumeration for restriction counter
- */
-typedef struct {
- long incoming_bytes;
- long outgoing_bytes;
-} network_counter_s;
-
-/**
- * @brief Enumeration for holding data usage information
- */
-typedef struct {
- network_counter_s cnt;
- network_restriction_s rst;
-} network_common_info;
-
-/**
- * @brief Set restriction information
- * @details Set and apply restriction for application.
- * It will create new restriction or modify existing.
- * @param[in] app_id Application identifier, it's package name now
- * @param[in] restriction Restriction to apply for application in foreground mode
- * At least one of the restriction should be setted.
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_restriction_s
- * @see #network_remove_restriction
- * @see #network_remove_restriction_by_iftype
- */
-network_error_e network_set_restriction(const char *app_id,
- const network_restriction_s *restriction);
-
-/**
- * @brief Structure for information on restrictions.
- * @details
- * app_id - application identification - copy it if you in
- * callback function, don't store raw pointer on it
- * iftype - type of network interface
- */
-typedef struct {
- const char *app_id;
- network_iface_e iftype;
- network_restriction_state rst_state;
- int rcv_limit;
- int send_limit;
-} network_restriction_info_s;
-
-/**
- * @brief callback for processing information of restrictions
- */
-typedef network_cb_ret_e(*network_restriction_cb)(
- const network_restriction_info_s *info, void *user_data);
-
-/**
- * @brief Restrictions enumerate function
- * @param[in] restriction_db The callback is called for each application that restrcited now
- * @param[in] user_data User data will be passed to the callback function
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_restriction_cb
- */
-network_error_e network_restriction_foreach(network_restriction_cb restriction_cb,
- void *user_data);
-
-/**
- * @brief Remove existing restriction for application
- * @details Remove existing restriction for application
- * It will delete restriction rule in kernel
- * @param[in] app_id Application identifier, it's package name
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_set_restriction
- * @see #network_remove_restriction_by_iftype
- */
-network_error_e network_remove_restriction(const char *app_id);
-
-/**
- * @brief Remove existing restriction for application from interface type
- * @details Remove existing restriction for application
- * It will delete restriction rule in kernel
- * @param[in] app_id Application identifier, it's package name
- * @param[in] iftype Interface type
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_iface_e
- * @see #network_set_restriction
- * @see #network_remove_restriction_by_iftype
- */
-network_error_e network_remove_restriction_by_iftype(const char *app_id,
- const network_iface_e iftype);
-
-/**
- * @brief Exclude restriction for application
- * @details Exclude restriction for application
- * It will exclude restriction rule in kernel
- * @param[in] app_id Application identifier, it's package name
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_OK Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_set_restriction
- * @see #network_exclude_restriction_by_iftype
- */
-network_error_e network_exclude_restriction(const char *app_id);
-
-/**
- * @brief Exclude restriction for application from interface type
- * @details Exclude restriction for application
- * It will exclude restriction rule in kernel
- * @param[in] app_id Application identifier, it's package name
- * @param[in] iftype Interface type
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_OK Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_iface_e
- * @see #network_set_restriction
- * @see #network_exclude_restriction_by_iftype
- */
-network_error_e network_exclude_restriction_by_iftype(
- const char *app_id, const network_iface_e iftype);
-
-/**
- * @brief Structure for network activity information
- */
-typedef struct {
- int type; /*<< ingress/egress */
- char *appid;
- int iftype;
- int bytes;
-} network_activity_info_s;
-
-/**
- * @brief callback for network activity information of packet
- */
-typedef network_cb_ret_e(*network_activity_cb)(network_activity_info_s *info);
-
-/**
- * @brief Register activity callback
- * @details This function registering callback which invokes per every packet.
- * Function creates new reading thread and returns.
- * @param[in] activity_cb Invoked per every packet with NET_ACTIVITY channel
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_activity_cb
- */
-network_error_e network_register_activity_cb(network_activity_cb activity_cb);
-
-/**
- * @brief After invoking this function, application will be in the monitored scope
- * @details It creates an appropriate cgroup,
- * it generates classid for the network performance control.
- * It creates a unit file for the systemd.
- * @param[in] app_id Application identifier, it's package name now
- * @param[in] pid Pid to put in to cgroup, or self pid of 0
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- */
-network_error_e network_join_app_performance(const char *app_id, const pid_t pid);
-
-/**
- * @brief Update the resourced counters and stores it in the database.
- * @details Updates going asynchronyusly, it mean client can't be sure was
- * counters updated or not after this function finished.
- * To handle finish of the update process client need to
- * regist callback function
- * @see network_register_update_cb.
- * Next counters updating will procced according to resourced
- * update period, unless another network_update_statisitcs is
- * not invoked.
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- */
-network_error_e network_update_statistics(void);
-
-/*
- * @brief Counters update information
- * @details This structure is needed to prevent client API from modification
- * in case of any information about update will be required.
- */
-struct network_update_info {
- /*dummy content*/
-};
-
-/**
- * @brief Callback for update counters
- */
-typedef network_cb_ret_e(*network_update_cb)(
- const struct network_update_info *info,
- void *user_data);
-
-/**
- * @brief Register callback for update counters.
- * @details Callback function will be called if
- * network_update_statistics is requested.
- * To stop callbacks invocation return NETWORK_CANCEL from
- * callback function or call @see network_unregister_update_cb.
- *
- * @param[in] user_data pointer to any data given to callback function.
- * Memory area should not be released until callback is unregistered.
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @code
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <rd-network.h>
-
-network_cb_ret_e network_update(const struct network_update_info *info,
- void *user_data)
-{
- char buf[50];
- char *str_data = user_data;
- printf("Callback updated. Stop yes/no?: ");
- scanf("%s", buf);
- if (strcmp(buf, "yes") == 0)
- return NETWORK_CANCEL;
-
- printf("user data is %s\n", user_data);
-
- return NETWORK_CONTINUE;
-}
-
-int main(void)
-{
- network_error_e ret;
-
- ecore_init();
-
- char *user_data = (char *)malloc(1024);
-
- strcpy(user_data, "hello");
-
- ret = network_register_update_cb(network_update, (void *)user_data);
-
- network_update_statistics();
-
- ecore_main_loop_begin();
-
- free(user_data);
- ecore_shutdown();
-}
-
- * @endcode
- */
-network_error_e network_register_update_cb(network_update_cb update_cb,
- void *user_data);
-
-/**
- * @brief Unregister update callback.
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- */
-void network_unregister_update_cb(void);
-
-/**
- * @brief Structure for selection rule applied
- */
-typedef struct {
- unsigned char version;
- time_t from;
- time_t to;
- network_iface_e iftype;
- int granularity;
-} network_selection_rule_s;
-
-/**
- * @brief Bundle structure for bringing all together application identification and properties
- * @details
- * app_id - application identification - copy it if you in
- * callback function, don't store raw pointer on it
- * iface - interface name, NULL means all interfaces,
- * don't store raw pointer on it in the callback function, copy it by value
- * interval - time interval for given result, NULL means entire interval
- * foreground - foreground restrictions and counters
- * background - background restrictions and counters
- */
-typedef struct {
- const char *app_id;
- network_iface_e iftype;
- network_tm_interval_s *interval;
- network_common_info foreground;
- network_common_info background;
- network_roaming_e roaming;
- network_hw_net_protocol_e hw_net_protocol_type;
-} network_info_s;
-
-/**
- * @brief Callback for enumerate counters and restrictions
- */
-typedef network_cb_ret_e(*network_info_cb) (const network_info_s *info,
- void *user_data);
-
-/**
- * @brief Data usage enumerate function
- * @details The callback is called for each application that used network
- * in between timestamps specified.
- * If interface name is not specified, each application will only appear
- * once with the total traffic used over all interfaces.
- * @param[in] rule Selection rule
- * @param[in] info_cb The callback is called for each application
- * that used network in between timestamps specified
- * @param[in] user_data User data will be passed to the callback function
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_selection_rule_s
- * @see #network_info_cb
- * @see #network_details_foreach
- */
-network_error_e network_foreach(const network_selection_rule_s *rule,
- network_info_cb info_cb, void *user_data);
-
-/**
- * @brief Data usage details enumerate function
- * @detail
- * If interface name is specified in rule, the callback will be called
- * exactly 1 time with the total traffic counts for that interface
- * by specified application in the specified time interval.
- * If interface name is not specified, the callback will be called once
- * for each interface used by application during the specified interval.
- * It could be 0 if the application did not use any network interfaces
- * during that period.
- * @param[in] app_id Application id
- * @param[in] rule Selection rule
- * @param[in] info_cb The callback is called for each application
- * that used network in between timestamps specified
- * @param[in] user_data User data will be passed to the callback function
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_selection_rule_s
- * @see #network_info_cb
- * @s22 #network_foreach
- */
-network_error_e network_details_foreach(const char *app_id,
- network_selection_rule_s *rule,
- network_info_cb info_cb,
- void *user_data);
-
-/**
- * @brief Structure for reset rule
- * @details It's statistics erasing description.
- * app_id - Erase statistics per appropriate app_id.
- * app_id can be NULL in this case erasing all datas
- * iftype - Erase statistics per appropriate network interface type
- * #network_iface_e, if iftype is NETWORK_IFACE_LAST_ELEM - erase all
- * NETWORK_IFACE_UNKNOW - means undetermined interface on moment of storing data.
- * interval - It's time interval, @see network_tm_interval_s.
- * It should be set. Zero interval since 0 till 0 means entire interval.
- * connection_state - It's mask on time interval.
- * Possible variation LAST and TOTAL for send and received data.
- */
-typedef struct {
- unsigned char version;
- char *app_id;
- network_iface_e iftype;
- network_tm_interval_s *interval;
- network_connection_period_e connection_state;
-} network_reset_rule_s;
-
-/**
- * @brief Reset data usage information
- * @param[in] rule Reset rule. It's statistics erasing description
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_reset_rule_s
- */
-network_error_e network_reset(const network_reset_rule_s *rule);
-
-/**
- * @brief Reset filter for quota
- * @details
- * app_id is mandatory field
- * iftype interface type, NETWORK_IFACE_UNKNOWN
- * interface is not valid parameter, use NETWORK_IFACE_ALL instead
- * roaming_type roaming type
- * If user will not specify last 2 fields (UNKNOWN by default),
- * neither quota with defined interface nor
- * quota with defined roaming state will be removed.
- */
-typedef struct {
- const char *app_id;
- network_iface_e iftype;
- network_roaming_e roaming;
-} network_quota_reset_rule_s;
-
-/**
- * @brief Remove datausage quota by quota rule
- * @param[in] rule reset filter for quota
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_quota_reset_rule_s
- * @see #network_set_quota
- * @see #network_remove_quota_by_iftype
- */
-network_error_e network_remove_quota(
- const network_quota_reset_rule_s *rule);
-
-/**
- * @brief Remove datausage quota by quota rule
- * @param[in] app_id Application id
- * @param[in] iftype Interface type
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_quota_reset_rule_s
- * @see #network_set_quota
- * @see #network_remove_quota
- */
-network_error_e network_remove_quota_by_iftype(
- const char *app_id, const network_iface_e iftype);
-
-/**
- * @brief Datausage quota
- * @details
- * time_period - time interval for quota, use predefined quota
- * #network_quota_s_period_t
- * snd_quota - quota for outcoming data
- * rcv_quota - quota for incoming data
- * warning_send_threshold - threshold for warning notification on engress bytes
- * warning_rcv_threshold - threshold for warning notification on ingress bytes
- * value - WARNING_THRESHOLD_UNDEF means no threshold
- * - WARNING_THRESHOLD_DEFAULT means resourced will be
- * responsible for evaluation threshold value
- * The threshold value is amount of bytes remaining till blocking
- * quota_type - at present it can be foreground quota or background
- * iftype - network interface type
- * start_time - quota processing activation time, if NULL current time is used
- */
-typedef struct {
- int time_period;
- int64_t snd_quota;
- int64_t rcv_quota;
- int snd_warning_threshold;
- int rcv_warning_threshold;
- network_state_e quota_type;
- network_iface_e iftype;
- time_t *start_time;
- network_roaming_e roaming_type;
-} network_quota_s;
-
-/**
- * @brief Set datausage quota
- * @details This function will set time interval based quota for data usage
- * Restriction will be applied in case of exceeding of the quota
- * during time interval
- * @param app_id[in] Application identifier, it's package name
- * @param quotas[in] Time interval based restriction for data usage
- *
- * @return 0 on success, otherwise a negative error value
- * @retval #NETWORK_ERROR_NONE Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_OUT_OF_MEMORY Out of memory
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- * @retval #NETWORK_ERROR_NO_DATA Success, but no data
- * @retval #NETWORK_ERROR_UNINITIALIZED Cgroup doesn't mounted or daemon is not started
- * @retval #NETWORK_ERROR_NOTIMPL No implemented yet error
- * @retval #NETWORK_ERROR_NONMONITOR Process don't show watchdog popup
- *
- * @see #network_set_quota
- * @see #network_remove_quota
- * @see #network_remove_quota_by_iftype
- */
-network_error_e network_set_quota(const char *app_id,
- const network_quota_s *quota);
-
-
-/**
- *
- * This function get restriction state.
- * State can be following:
- * NETWORK_RESTRICTION_UNDEFINDED - means restriction wasn't set
- * NETWORK_RESTRICTION_ACTIVATED - means restriction activated
- * NETWORK_RESTRICTION_EXCLUDED - restriction has been excluded
- *
- * @code
- * #include <rd-network.h>
- *
- * int is_whole_network_restricted()
- * {
- * network_restriction_state state;
- * network_error_r ret_code = network_get_restriction_state(
- * RESOURCED_ALL_APP, NETWORK_IFACE_ALL, &state);
- * if (ret_code != NETWORK_ERROR_NONE &&
- * state == NETWORK_RESTRICTION_ACTIVATED)
- * return 1;
- * return 0;
- * }
- *
- * @endcode
- *
- * @retval #NETWORK_ERROR_OK Successful
- * @retval #NETWORK_ERROR_FAIL General error
- * @retval #NETWORK_ERROR_DB_FAILED Database error
- * @retval #NETWORK_ERROR_INVALID_PARAMETER Invalid parameter
- *
- * @see #network_iface_e
- * @see #network_restriction_state
- * @see #network_set_restriction
- * @see #network_exclude_restriction_by_iftype
- *
- */
-network_error_e network_get_restriction_state(const char *pkg_id,
- network_iface_e iftype, network_restriction_state *state);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __RD_NETWORK_H__
diff --git a/packaging/resourced-logging.service b/packaging/resourced-logging.service
deleted file mode 100644
index fe0b64dd..00000000
--- a/packaging/resourced-logging.service
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=Logging Initialization
-After=resourced.service
-
-[Service]
-Type=oneshot
-ExecStartPre=/bin/sleep 1
-ExecStart=/usr/bin/dbus-send --type=signal --system /Org/Tizen/ResourceD/Logging org.tizen.resourced.logging.LoggingInit
-
-[Install]
-WantedBy=graphical.target
diff --git a/packaging/resourced.service b/packaging/resourced.service
index 12475c78..c9454bcb 100644
--- a/packaging/resourced.service
+++ b/packaging/resourced.service
@@ -5,6 +5,7 @@ Wants=tizen-system.target
[Service]
Type=notify
+EnvironmentFile=/run/tizen-mobile-env
Environment="CGROUP_MEMORY_SWAP=/sys/fs/cgroup/memory/swap"
Environment="SWAPFILE=/dev/zram0"
ExecStartPre=-/bin/mkdir -pm 755 $CGROUP_MEMORY_SWAP
diff --git a/packaging/resourced.spec b/packaging/resourced.spec
index ca104137..0b2c5332 100644
--- a/packaging/resourced.spec
+++ b/packaging/resourced.spec
@@ -9,35 +9,42 @@ Source1: resourced.service
Source2: resourced-zram.service
Source5: resourced_swapoff.service
Source6: resourced-cpucgroup.service
-Source8: resourced-logging.service
%define powertop_state OFF
%define cpu_module ON
-%define vip_agent_module ON
%define timer_slack ON
-%define logging_module OFF
+
+%define vip_agent_module ON
+
+%define logging_module ON
%define logging_memory OFF
-%define logging_cpu OFF
+%define logging_cpu ON
+
%define memory_module ON
-%define memory_cgroup OFF
%define swap_module OFF
+%define memory_vmpressure ON
+
%define network_state OFF
-%define telephony_feature OFF
%define tethering_feature OFF
%if "%{?tizen_profile_name}" == "mobile"
%define swap_module OFF
+ %define memory_vmpressure OFF
%define network_state OFF
- %define telephony_feature OFF
%define tethering_feature OFF
-
%endif
%if "%{?tizen_profile_name}" == "wearable"
- %define swap_module OFF
+ %define swap_module ON
+ %define memory_vmpressure ON
%define network_state OFF
- %define telephony_feature OFF
+%endif
+%if "%{?tizen_profile_name}" == "tv"
+ %define swap_module ON
+ %define memory_vmpressure ON
+ %define network_state OFF
+ %define tethering_feature OFF
%endif
%if 0%{?tizen_build_binary_release_type_eng}
@@ -59,11 +66,13 @@ BuildRequires: pkgconfig(vconf)
BuildRequires: pkgconfig(vconf-internal-keys)
BuildRequires: pkgconfig(ecore)
BuildRequires: pkgconfig(ecore-file)
+BuildRequires: pkgconfig(eina)
BuildRequires: pkgconfig(edbus)
-BuildRequires: pkgconfig(capi-network-connection)
BuildRequires: pkgconfig(libsystemd-daemon)
-BuildRequires: pkgconfig(eina)
-
+BuildRequires: pkgconfig(openssl)
+BuildRequires: pkgconfig(bundle)
+#only for data types
+BuildRequires: pkgconfig(tapi)
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
@@ -72,7 +81,7 @@ BuildRequires: pkgconfig(libsystemd-journal)
%endif
%description
-Resourced (Resource management daemon)
+Resourced daemon
%package resourced
Summary: Resource Daemon
@@ -87,15 +96,15 @@ Group: System/Libraries
Requires: %{name} = %{version}-%{release}
%description -n libresourced
-Library of resourced (Resource management daemon)
+Library for resourced (Resource Management Daemon)
%package -n libresourced-devel
Summary: Resource Daemon Library (Development)
Group: System/Libraries
-Requires: libresourced = %{version}-%{release}
+Requires: libresourced = %{version}-%{release}
%description -n libresourced-devel
-Library (Development) of resourced (Resource management daemon)
+Library (development) for resourced (Resource Management Daemon)
%prep
%setup -q
@@ -118,15 +127,29 @@ export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
-%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER} -DCMAKE_BUILD_TYPE=Release \
+%cmake . \
+ -DFULLVER=%{version} \
+ -DMAJORVER=${MAJORVER} \
+ -DCMAKE_BUILD_TYPE=Release \
-DEXCLUDE_LIST_FILE_NAME=%{exclude_list_file_name} \
- -DEXCLUDE_LIST_FULL_PATH=%{exclude_list_full_path} -DDATABASE_FULL_PATH=%{database_full_path} \
- -DEXCLUDE_LIST_OPT_FULL_PATH=%{exclude_list_opt_full_path} -DNETWORK_MODULE=%{network_state} -DSWAP_MODULE=%{swap_module} \
- -DPOWERTOP_MODULE=%{powertop_state} -DCPU_MODULE=%{cpu_module}\
- -DMEMORY_ENG=%{memory_eng} -DVIP_AGENT=%{vip_agent_module} -DTELEPHONY_FEATURE=%{telephony_feature} \
- -DTIMER_SLACK=%{timer_slack} -DLOGGING_MODULE=%{logging_module} -DLOGGING_MEMORY=%{logging_memory} \
- -DLOGGING_CPU=%{logging_cpu} -DDATAUSAGE_TYPE=NFACCT -DMEMORY_MODULE=%{memory_module} -DMEMORY_CGROUP=%{memory_cgroup} \
- -DTETHERING_FEATURE=%{tethering_feature}
+ -DEXCLUDE_LIST_FULL_PATH=%{exclude_list_full_path} \
+ -DEXCLUDE_LIST_OPT_FULL_PATH=%{exclude_list_opt_full_path} \
+ -DVIP_AGENT=%{vip_agent_module} \
+ -DSWAP_MODULE=%{swap_module} \
+ -DMEMORY_ENG=%{memory_eng} \
+ -DMEMORY_VMPRESSURE=%{memory_vmpressure} \
+ -DMEMORY_MODULE=%{memory_module} \
+ -DMEMORY_VMPRESSURE=%{memory_vmpressure} \
+ -DDATABASE_FULL_PATH=%{database_full_path} \
+ -DNETWORK_MODULE=%{network_state} \
+ -DTELEPHONY_FEATURE=%{telephony_feature} \
+ -DDATAUSAGE_TYPE=NFACCT \
+ -DLOGGING_MODULE=%{logging_module} \
+ -DLOGGING_MEMORY=%{logging_memory} \
+ -DLOGGING_CPU=%{logging_cpu} \
+ -DPOWERTOP_MODULE=%{powertop_state} \
+ -DCPU_MODULE=%{cpu_module} \
+ -DTIMER_SLACK=%{timer_slack}
make %{?jobs:-j%jobs}
@@ -169,13 +192,6 @@ mkdir -p %{buildroot}/usr/share/powertop-wrapper/
cp -p %_builddir/%name-%version/src/powertop-wrapper/header.html %{buildroot}/usr/share/powertop-wrapper
%endif
-%if %{?logging_module} == ON
-#logging service file
-mkdir -p %{buildroot}%{_libdir}/systemd/system/graphical.target.wants
-install -m 0644 %SOURCE8 %{buildroot}%{_libdir}/systemd/system/resourced-logging.service
-ln -s ../resourced-logging.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/resourced-logging.service
-%endif
-
%pre resourced
if [ "$1" = "2" ]; then # upgrade begins
systemctl stop resourced.service
@@ -187,12 +203,13 @@ fi
init_vconf()
{
- vconftool set -t bool db/private/resourced/wifi_statistics 1 -i -f -s resourced
- vconftool set -t bool db/private/resourced/datacall 1 -i -f -s resourced
- vconftool set -t bool db/private/resourced/datacall_logging 1 -i -f -s resourced
- vconftool set -t int db/private/resourced/datausage_timer 60 -i -f -s resourced
- vconftool set -t string db/private/resourced/new_limit "" -u 5000 -f -s resourced
- vconftool set -t string db/private/resourced/delete_limit "" -u 5000 -f -s resourced
+ vconftool set -t bool db/private/resourced/wifi_statistics 1 -i -f -s tizen::vconf::platform::rw
+ vconftool set -t bool db/private/resourced/datacall 1 -i -f -s tizen::vconf::platform::rw
+ vconftool set -t bool db/private/resourced/datacall_logging 1 -i -f -s tizen::vconf::platform::rw
+ vconftool set -t int db/private/resourced/datausage_timer 60 -i -f -s tizen::vconf::platform::rw
+ vconftool set -t string db/private/resourced/new_limit "" -u 5000 -f -s tizen::vconf::platform::rw
+ vconftool set -t string db/private/resourced/delete_limit "" -u 5000 -f -s tizen::vconf::platform::rw
+ vconftool set -t int db/private/resourced/network_db_entries 0 -i -f -s tizen::vconf::platform::rw
}
%if %{?network_state} == ON
@@ -211,11 +228,15 @@ fi
%files -n resourced
/usr/share/license/%{name}
+/etc/smack/accesses2.d/resourced.rule
%attr(-,root, root) %{_bindir}/resourced
%if %{?network_state} == ON
%config(noreplace) %attr(660,root,app) %{database_full_path}
%config(noreplace) %attr(660,root,app) %{database_full_path}-journal
/usr/bin/datausagetool
+ %config /etc/resourced/network.conf
+ /etc/opt/upgrade/500.resourced-datausage.patch.sh
+ %attr(700,root,root) /etc/opt/upgrade/500.resourced-datausage.patch.sh
%manifest resourced.manifest
%else
%manifest resourced_nodb.manifest
@@ -232,14 +253,11 @@ fi
%{_libdir}/systemd/system/graphical.target.wants/resourced-cpucgroup.service
%endif
%if %{?swap_module} == ON
+%config /etc/resourced/swap.conf
%{_libdir}/systemd/system/resourced-zram.service
%{_libdir}/systemd/system/graphical.target.wants/resourced-zram.service
%{_bindir}/resourced-zram.sh
%endif
-%if %{?logging_module} == ON
-%{_libdir}/systemd/system/resourced-logging.service
-%{_libdir}/systemd/system/graphical.target.wants/resourced-logging.service
-%endif
%if %{?vip_agent_module} == ON
%config /etc/resourced/vip-process.conf
%attr(-,root, root) %{_bindir}/vip-release-agent
@@ -262,10 +280,7 @@ fi
#proc-stat part
%{_libdir}/libproc-stat.so.*
#network part
-%if %{?network_state} == ON
%{_libdir}/libresourced.so.*
-%{_libdir}/librd-network.so.*
-%endif
#powertop-wrapper part
%if %{?powertop_state} == ON
%{_libdir}/libpowertop-wrapper.so.*
@@ -279,13 +294,10 @@ fi
%{_includedir}/system/proc_stat.h
%{_libdir}/libproc-stat.so
#network part
-%if %{?network_state} != OFF
+%if %{?network_state} == ON
%{_includedir}/system/data_usage.h
-%{_includedir}/system/rd-network.h
-%{_libdir}/libresourced.so
-%{_libdir}/librd-network.so
-%config /etc/resourced/network.conf
%endif
+%{_libdir}/libresourced.so
#powertop-wrapper part
%if %{?powertop_state} == ON
%{_includedir}/system/powertop-dapi.h
diff --git a/packaging/resourced_swapoff.service b/packaging/resourced_swapoff.service
index ff164c89..1b95268b 100644
--- a/packaging/resourced_swapoff.service
+++ b/packaging/resourced_swapoff.service
@@ -4,6 +4,8 @@ After=tizen-system.target
Wants=tizen-system.target
[Service]
+Type=simple
+EnvironmentFile=/run/tizen-system-env
ExecStart=/usr/bin/resourced -s 1 -u 60
Restart=always
RestartSec=0
diff --git a/resourced.manifest b/resourced.manifest
index 56400ee2..f4624b6b 100644
--- a/resourced.manifest
+++ b/resourced.manifest
@@ -3,10 +3,26 @@
<domain name="resourced"/>
<provide>
<label name="resourced::db"/>
+ <label name="resourced::systeminfo"/>
</provide>
+ <request>
+ <smack request="resourced::systeminfo" type="rw"/>
+ </request>
</define>
<assign>
<filesystem path="/opt/usr/dbspace/.resourced-datausage.db*" label="resourced::db"/>
+ <dbus name="org.tizen.resourced" own="resourced" bus="system">
+ <node name="/Org/Tizen/ResourceD/Process">
+ <interface name="org.tizen.resourced.process">
+ <method name="ProcMemoryUsage">
+ <annotation name="com.tizen.smack" value="resourced::systeminfo" />
+ </method>
+ <method name="ProcCpuUsage">
+ <annotation name="com.tizen.smack" value="resourced::systeminfo" />
+ </method>
+ </interface>
+ </node>
+ </dbus>
</assign>
<request>
<domain name="resourced"/>
diff --git a/resourced.pc.in b/resourced.pc.in
deleted file mode 100644
index 11dfe0e4..00000000
--- a/resourced.pc.in
+++ /dev/null
@@ -1,16 +0,0 @@
-# Package Information for pkg-config
-#
-# Copyright (c) 2012 Samsung Electronics Co., Ltd.
-# All rights reserved.
-#
-
-libdir=@LIB_INSTALL_DIR@
-includedir=@INCLUDEDIR@
-
-Name: @PC_NAME_DEPRECATED@
-Description: Tizen Resource management Daemon
-Version: @VERSION@
-Requires: @PC_REQUIRED@
-Libs: -L${libdir} @PC_PROVIDED_LIBS@
-Cflags: @PC_CFLAGS@
-
diff --git a/resourced.rule b/resourced.rule
index d6cbe41e..f326c031 100644
--- a/resourced.rule
+++ b/resourced.rule
@@ -1,3 +1,9 @@
-resourced com.samsung.setting::private r
-resourced system::vconf_inhouse rw
-resourced system-apps r \ No newline at end of file
+resourced tizen::vconf::public::r::platform::rw rw
+resourced system-apps r
+resourced sys-assert::core rwxat
+resourced system::media rwxat
+resourced system::media::root rwxat
+resourced telephony_framework::api_network r
+resourced telephony_framework::api_manager r
+resourced telephony_framework::api_modem r
+resourced telephony_framework::api_sim r
diff --git a/resourced_nodb.manifest b/resourced_nodb.manifest
index 3256181b..94675d92 100644
--- a/resourced_nodb.manifest
+++ b/resourced_nodb.manifest
@@ -1,5 +1,28 @@
<manifest>
-<request>
- <domain name="_"/>
-</request>
+ <define>
+ <domain name="resourced"/>
+ <provide>
+ <label name="resourced::systeminfo"/>
+ </provide>
+ <request>
+ <smack request="resourced::systeminfo" type="rw"/>
+ </request>
+ </define>
+ <assign>
+ <dbus name="org.tizen.resourced" own="resourced" bus="system">
+ <node name="/Org/Tizen/ResourceD/Process">
+ <interface name="org.tizen.resourced.process">
+ <method name="ProcMemoryUsage">
+ <annotation name="com.tizen.smack" value="resourced::systeminfo" />
+ </method>
+ <method name="ProcCpuUsage">
+ <annotation name="com.tizen.smack" value="resourced::systeminfo" />
+ </method>
+ </interface>
+ </node>
+ </dbus>
+ </assign>
+ <request>
+ <domain name="resourced"/>
+ </request>
</manifest>
diff --git a/src/common/appid-helper.c b/src/common/appid-helper.c
index 091a1041..915bd2ec 100644
--- a/src/common/appid-helper.c
+++ b/src/common/appid-helper.c
@@ -17,15 +17,27 @@
*
*/
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#define BASE_NAME_PREFIX "com.samsung."
#define DOT_DELIMETER '.'
-static int is_base_name(const char *appid)
+/*
+ * no need to extract in case of com.facebook, com.opera.
+ * org.tizen
+ * but in case of samsung.Engk10bghd we will do it,
+ * It's better here to pass appid as is to setting,
+ * but in this case setting should group it, because
+ * several appid is possible in one package.
+ * */
+static bool is_base_name(const char *appid)
{
- return strstr(appid, BASE_NAME_PREFIX) != NULL;
+ char *dot = index(appid, DOT_DELIMETER);
+ if (!dot)
+ return false;
+
+ return index(dot, DOT_DELIMETER) != NULL;
}
void extract_pkgname(const char *appid, char *pkgname,
diff --git a/src/common/cgroup.c b/src/common/cgroup.c
index 9958f22e..3fb06458 100644
--- a/src/common/cgroup.c
+++ b/src/common/cgroup.c
@@ -81,6 +81,40 @@ resourced_ret_c place_pid_to_cgroup(const char *cgroup_subsystem,
return place_pid_to_cgroup_by_fullpath(buf, pid);
}
+resourced_ret_c place_pidtree_to_cgroup(const char *cgroup_subsystem,
+ const char *cgroup_name, const int pid)
+{
+ char buf[MAX_PATH_LENGTH];
+
+ /*/proc/%d/task/%d/children */
+ char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
+ char pidbuf[MAX_DEC_SIZE(int)];
+ resourced_ret_c ret;
+
+ FILE *f;
+
+ snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
+ /* place parent */
+ ret = place_pid_to_cgroup_by_fullpath(buf, pid);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "Failed to put parent process %d into %s cgroup", pid, cgroup_name);
+
+ snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN,
+ pid, pid);
+ f = fopen(child_buf, "r");
+ ret_value_msg_if(!f, RESOURCED_ERROR_FAIL, "Failed to get child pids!");
+ while (fgets(pidbuf, sizeof(pidbuf), f) != NULL) {
+ int child_pid = atoi(pidbuf);
+ ret_value_msg_if(child_pid < 0, RESOURCED_ERROR_FAIL,
+ "Invalid child pid!");
+ resourced_ret_c ret = place_pid_to_cgroup_by_fullpath(buf, child_pid);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "Failed to put parent process %d into %s cgroup", pid, cgroup_name);
+
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
int cgroup_write_node(const char *cgroup_name,
const char *file_name, unsigned int value)
{
@@ -113,7 +147,11 @@ int make_cgroup_subdir(char* parentdir, char* cgroup_name, int *exists)
int cgroup_exists = 0, ret = 0;
char buf[MAX_PATH_LENGTH];
- ret = snprintf(buf, sizeof(buf), "%s/%s", parentdir, cgroup_name);
+ if (parentdir)
+ ret = snprintf(buf, sizeof(buf), "%s/%s", parentdir, cgroup_name);
+ else
+ ret = snprintf(buf, sizeof(buf), "%s", cgroup_name);
+
ret_value_msg_if(ret > sizeof(buf), RESOURCED_ERROR_FAIL,
"Not enought buffer size for %s%s", parentdir, cgroup_name);
diff --git a/src/common/cgroup.h b/src/common/cgroup.h
index c57bf67d..ea6e5a7a 100644
--- a/src/common/cgroup.h
+++ b/src/common/cgroup.h
@@ -27,7 +27,9 @@
#ifndef _CGROUP_LIBRARY_CGROUP_H_
#define _CGROUP_LIBRARY_CGROUP_H_
-#define DEFAULT_CGROUP "/sys/fs/cgroup"
+
+#define DEFAULT_CGROUP "/sys/fs/cgroup"
+#define PROC_TASK_CHILDREN "/proc/%d/task/%d/children"
/**
* @desc Get one unsigned int value from cgroup
@@ -78,10 +80,9 @@ int make_cgroup_subdir(char* parentdir, char* cgroup_name, int *cgroup_exists);
int mount_cgroup_subsystem(char* source, char* mount_point, char* opts);
/**
- * @desc mount cgroup,
- * @param source -cgroup name
- * @param mount_point - cgroup path
- * @param opts - mount options
+ * @desc write pid into cgroup_subsystem/cgroup_name file,
+ * @param cgroup_subsystem path to /sys/fs/cgroup/subsystem
+ * @param cgroup_name - name in /sys/fs/cgroup/subsystem/
* @return negative value if error
*/
resourced_ret_c place_pid_to_cgroup(const char *cgroup_subsystem,
@@ -90,4 +91,12 @@ resourced_ret_c place_pid_to_cgroup(const char *cgroup_subsystem,
resourced_ret_c place_pid_to_cgroup_by_fullpath(const char *cgroup_full_path,
const int pid);
+/**
+ * @desc doing the same as @see place_pid_to_cgroup,
+ * but also put into cgroup first level child processes
+ */
+resourced_ret_c place_pidtree_to_cgroup(const char *cgroup_subsystem,
+ const char *cgroup_name, const int pid);
+
+
#endif /*_CGROUP_LIBRARY_CGROUP_H_*/
diff --git a/src/common/const.h b/src/common/const.h
index 4c943964..8e743dfd 100644
--- a/src/common/const.h
+++ b/src/common/const.h
@@ -20,9 +20,6 @@
/*
* @file: const.h
*
- * @desc Application stat entity
- * @version 1.0
- *
*/
#ifndef _RESOURCED_CONST_H
@@ -34,12 +31,12 @@
#define MAX_PATH_LENGTH 512
#define MAX_NAME_LENGTH 256
+#define MAX_IFACE_LENGTH 32
#define COMMA_DELIMETER ","
#define COUNTER_UPDATE_PERIOD 60
#define FLUSH_PERIOD 60
-#define STORE_DELAY_INTERVAL 1
#define NONE_QUOTA_ID 0
@@ -56,6 +53,9 @@ enum resourced_reserved_classid {
applications */
RESOURCED_TETHERING_APP_CLASSID, /**< it uses in user space logic
for counting tethering traffic */
+ RESOURCED_FOREGROUND_APP_CLASSID, /* it will used for special cgroup,
+ blocked cgroup */
+ RESOURCED_BACKGROUND_APP_CLASSID,
RESOURCED_RESERVED_CLASSID_MAX,
};
@@ -64,6 +64,8 @@ enum resourced_counter_state {
RESOURCED_FORCIBLY_FLUSH_STATE = 1 << 1,
RESOURCED_FORCIBLY_QUIT_STATE = 1 << 2,
RESOURCED_NET_BLOCKED_STATE = 1 << 3,
+ RESOURCED_CHECK_QUOTA = 1 << 4,
+ RESOURCED_UPDATE_REQUESTED = 1 << 5,
};
#endif /* _RESOURCED_CONST_H */
diff --git a/src/common/daemon-options.h b/src/common/daemon-options.h
index a046dd6f..3bc60ba2 100644
--- a/src/common/daemon-options.h
+++ b/src/common/daemon-options.h
@@ -31,7 +31,6 @@
#include <signal.h>
struct daemon_opts {
- sig_atomic_t is_update_quota;
sig_atomic_t datacall_logging; /**< type of rsml_datacall_logging_option */
sig_atomic_t start_daemon;
sig_atomic_t update_period;
diff --git a/src/common/edbus-handler.c b/src/common/edbus-handler.c
index 85b6f275..6bf35730 100644
--- a/src/common/edbus-handler.c
+++ b/src/common/edbus-handler.c
@@ -35,6 +35,8 @@
struct edbus_list{
char *signal_name;
+ char *signal_path;
+
E_DBus_Signal_Handler *handler;
};
@@ -66,6 +68,11 @@ static int append_variant(DBusMessageIter *iter,
for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
switch (*ch) {
+ case 'b':
+ int_type = atoi(param[i]);
+ dbus_message_iter_append_basic(iter,
+ DBUS_TYPE_BOOLEAN, &int_type);
+ break;
case 'i':
int_type = atoi(param[i]);
dbus_message_iter_append_basic(iter,
@@ -329,19 +336,20 @@ static void unregister_edbus_signal_handle(void)
}
int register_edbus_signal_handler(const char *path, const char *interface,
- const char *name, E_DBus_Signal_Cb cb)
+ const char *name, E_DBus_Signal_Cb cb, void *user_data)
{
Eina_List *search;
struct edbus_list *entry;
E_DBus_Signal_Handler *handler;
EINA_LIST_FOREACH(edbus_handler_list, search, entry) {
- if (entry != NULL && strncmp(entry->signal_name, name, strlen(name)) == 0)
+ if (entry != NULL && strncmp(entry->signal_name, name, strlen(name)) == 0 &&
+ strncmp(entry->signal_path, path, strlen(path)) == 0)
return RESOURCED_ERROR_FAIL;
}
handler = e_dbus_signal_handler_add(edbus_conn, NULL, path,
- interface, name, cb, NULL);
+ interface, name, cb, user_data);
if (!handler) {
_E("fail to add edbus handler");
@@ -359,19 +367,34 @@ int register_edbus_signal_handler(const char *path, const char *interface,
if (!entry->signal_name) {
_E("Malloc failed");
- free(entry);
- return -1;
+ goto release_entry;
+ }
+
+ entry->signal_path = strndup(path, strlen(path));
+ if (!entry->signal_path) {
+ _E("Malloc failed");
+ goto release_name;
}
entry->handler = handler;
edbus_handler_list = eina_list_prepend(edbus_handler_list, entry);
if (!edbus_handler_list) {
_E("eina_list_prepend failed");
- free(entry->signal_name);
- free(entry);
- return RESOURCED_ERROR_FAIL;
+ goto release_path;
}
+
return RESOURCED_ERROR_NONE;
+
+release_path:
+ free(entry->signal_path);
+
+release_name:
+ free(entry->signal_name);
+
+release_entry:
+
+ free(entry);
+ return RESOURCED_ERROR_FAIL;
}
int broadcast_edbus_signal_str(const char *path, const char *interface,
@@ -476,6 +499,19 @@ resourced_ret_c edbus_add_methods(const char *path,
return RESOURCED_ERROR_NONE;
}
+resourced_ret_c edbus_message_send(DBusMessage *msg)
+{
+ DBusPendingCall *pending;
+
+ pending = e_dbus_message_send(edbus_conn, msg, NULL, -1, NULL);
+ if (!pending) {
+ _E("sending message over dbus failed, connection disconnected!");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
{
DBusError err;
diff --git a/src/common/edbus-handler.h b/src/common/edbus-handler.h
index e6205212..a789563f 100644
--- a/src/common/edbus-handler.h
+++ b/src/common/edbus-handler.h
@@ -94,6 +94,9 @@ struct edbus_object {
#define SYSTEM_POPUP_PATH_WATCHDOG SYSTEM_POPUP_PATH_NAME"/System"
#define SYSTEM_POPUP_IFACE_WATCHDOG SYSTEM_POPUP_BUS_NAME".System"
+#define SYSTEM_POPUP_PATH_DATAUSAGE SYSTEM_POPUP_PATH_NAME"/DataUsage"
+#define SYSTEM_POPUP_IFACE_DATAUSAGE SYSTEM_POPUP_BUS_NAME".DataUsage"
+
/*
* Deviced
*/
@@ -104,6 +107,14 @@ struct edbus_object {
#define DEVICED_PATH_DISPLAY "/Org/Tizen/System/DeviceD/Display"
#define DEVICED_INTERFACE_DISPLAY DEVICED_BUS_NAME".display"
+/*
+ * 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_LCD_ON "LCDOn"
#define SIGNAL_LCD_OFF "LCDOff"
@@ -130,7 +141,7 @@ int dbus_method_async(const char *dest, const char *path,
const char *sig, char *param[]);
int register_edbus_signal_handler(const char *path, const char *interface,
- const char *name, E_DBus_Signal_Cb cb);
+ const char *name, E_DBus_Signal_Cb cb, void *user_data);
E_DBus_Interface *get_edbus_interface(const char *path);
pid_t get_edbus_sender_pid(DBusMessage *msg);
int broadcast_edbus_signal_str(const char *path, const char *interface,
@@ -140,6 +151,7 @@ int broadcast_edbus_signal(const char *path, const char *interface,
resourced_ret_c edbus_add_methods(const char *path,
const struct edbus_method *const edbus_methods,
const size_t size);
+resourced_ret_c edbus_message_send(DBusMessage *msg);
int register_edbus_interface(struct edbus_object *object);
void edbus_init(void);
diff --git a/src/common/macro.h b/src/common/macro.h
index f47111c0..73740808 100644
--- a/src/common/macro.h
+++ b/src/common/macro.h
@@ -37,7 +37,9 @@
#include <stdio.h>
#include <config.h>
+#ifndef API
#define API __attribute__((visibility("default")))
+#endif
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
@@ -68,6 +70,15 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
sizeof(type) <= 8 ? 20 : \
sizeof(int[-2*(sizeof(type) > 8)])))
+#define SET_BIT(a, bit) \
+ ((a) |= (bit))
+
+#define UNSET_BIT(a, bit) \
+ ((a) &= ~(bit))
+
+#define CHECK_BIT(a, bit) \
+ ((a) & (bit))
+
#define ret_msg_if(expr, fmt, arg...) do { \
if (expr) { \
_E(fmt, ##arg); \
@@ -108,14 +119,15 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
* destination should not be on heap.
* Destination will be null terminated
*/
-#define STRING_SAVE_COPY(destination, source) \
- do { \
+#define STRING_SAVE_COPY(destination, source) do { \
+ if (destination && source) { \
size_t null_pos = strlen(source); \
strncpy(destination, source, sizeof(destination)); \
null_pos = sizeof(destination) - 1 < null_pos ? \
sizeof(destination) - 1 : null_pos; \
destination[null_pos] = '\0'; \
- } while(0)
+ } \
+} while (0)
/* FIXME: Do we really need pointers? */
#define array_foreach(key, type, array) \
@@ -141,9 +153,9 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
for (elem = head, node = NULL; elem && ((node = elem->data) != NULL); elem = elem->next, node = NULL)
#define gslist_for_each_safe(head, elem, elem_next, node) \
- for (elem = head, elem_next = g_list_next(elem), node = NULL; \
+ for (elem = head, elem_next = g_slist_next(elem), node = NULL; \
elem && ((node = elem->data) != NULL); \
- elem = elem_next, elem_next = g_list_next(elem), node = NULL)
+ elem = elem_next, elem_next = g_slist_next(elem), node = NULL)
#define DB_ACTION(command) do { \
if ((command) != SQLITE_OK) { \
diff --git a/src/common/module-data.c b/src/common/module-data.c
index ce81e5f2..da052ed3 100644
--- a/src/common/module-data.c
+++ b/src/common/module-data.c
@@ -38,4 +38,5 @@ void init_modules_arg(struct modules_arg *marg, struct daemon_arg *darg)
ret_msg_if(marg == NULL || darg == NULL,
"Init modules argument failed\n");
marg->opts = darg->opts;
+ modules_data.darg = darg;
}
diff --git a/src/common/module-data.h b/src/common/module-data.h
index 37f8e9b8..8240f2cb 100644
--- a/src/common/module-data.h
+++ b/src/common/module-data.h
@@ -40,6 +40,7 @@ struct swap_module_data {
struct shared_modules_data {
struct counter_arg *carg;
+ struct daemon_arg *darg;
struct swap_module_data swap_data;
};
diff --git a/src/common/module.c b/src/common/module.c
index 33734bb6..5e8dfafc 100644
--- a/src/common/module.c
+++ b/src/common/module.c
@@ -113,3 +113,16 @@ void modules_exit(void *data)
_E("Fail to deinitialize [%s] module\n", 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;
+ _D("dump [%s] module\n", module->name);
+ if (module->dump)
+ module->dump(fp, mode, module->dump_data);
+ }
+}
diff --git a/src/common/module.h b/src/common/module.h
index 7387cd5d..8ff6c249 100644
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -38,6 +38,8 @@ struct module_ops {
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);
@@ -46,6 +48,7 @@ void remove_module(const struct module_ops *module);
void modules_check_runtime_support(void *data);
void modules_init(void *data);
void modules_exit(void *data);
+void modules_dump(FILE *fp, int mode);
const struct module_ops *find_module(const char *name);
diff --git a/src/common/notifier.h b/src/common/notifier.h
index 46f112a9..2d9798f2 100644
--- a/src/common/notifier.h
+++ b/src/common/notifier.h
@@ -26,16 +26,15 @@ enum notifier_type {
RESOURCED_NOTIFIER_APP_RESUME,
RESOURCED_NOTIFIER_APP_FOREGRD,
RESOURCED_NOTIFIER_APP_BACKGRD,
+ RESOURCED_NOTIFIER_APP_BACKGRD_ACTIVE,
RESOURCED_NOTIFIER_SERVICE_LAUNCH,
RESOURCED_NOTIFIER_APP_ACTIVE,
RESOURCED_NOTIFIER_APP_INACTIVE,
RESOURCED_NOTIFIER_APP_TERMINATE,
- RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID,
RESOURCED_NOTIFIER_SWAP_START,
- RESOURCED_NOTIFIER_SWAP_RESTART,
- RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP,
RESOURCED_NOTIFIER_LCD_ON,
RESOURCED_NOTIFIER_LCD_OFF,
+ RESOURCED_NOTIFIER_APP_PRELAUNCH,
RESOURCED_NOTIFIER_MAX,
};
diff --git a/src/common/swap-common.h b/src/common/swap-common.h
index 7760e5c3..e4516fd7 100644
--- a/src/common/swap-common.h
+++ b/src/common/swap-common.h
@@ -25,32 +25,20 @@
#ifndef __SWAP_COMMON_H__
#define __SWAP_COMMON_H__
-enum swap_status_type {
- SWAP_GET_TYPE,
- SWAP_GET_CANDIDATE_PID,
- SWAP_GET_STATUS,
- SWAP_CHECK_PID,
- SWAP_CHECK_CGROUP,
-};
-
enum {
SWAP_OFF,
SWAP_ON,
SWAP_ARG_END,
};
-enum {
- SWAP_FALSE,
- SWAP_TRUE,
-};
-
#ifdef SWAP_SUPPORT
-extern int swap_status(enum swap_status_type type, unsigned long *args);
+int swap_check_swap_pid(int pid);
#else
-static inline int swap_status(enum swap_status_type type, unsigned long *args)
+static inline int swap_check_swap_pid(int pid)
{
- return RESOURCED_ERROR_NONE;
+ return RESOURCED_ERROR_FAIL;
}
#endif /* SWAP_SUPPORT */
+
#endif /* __SWAP_COMMON_H__ */
diff --git a/src/common/trace.h b/src/common/trace.h
index bd56dff5..01cf347b 100644
--- a/src/common/trace.h
+++ b/src/common/trace.h
@@ -79,4 +79,8 @@
#define ETRACE_ERRNO_MSG(fmt, arg...) \
TRACE_RET_ERRCODE_MSG(E, -errno, fmt, ##arg)
+#define LOG_DUMP(fp, fmt, arg...) \
+ if (fp) fprintf(fp, fmt, ##arg); \
+ else _E(fmt, ##arg);
+
#endif /* _SYSTEM_RESOURCE_TRACE_H_ */
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index db677eac..47f413f2 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -28,6 +28,9 @@
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
#include "notifier.h"
#include "proc-main.h"
#include "proc-process.h"
@@ -47,7 +50,71 @@
#define CPU_CONF_FILE "/etc/resourced/cpu.conf"
#define CPU_CONF_SECTION "CONTROL"
#define CPU_CONF_PREDEFINE "PREDEFINE"
+#define CPU_CONF_BOOTING "BOOTING_PREDEFINE"
+#define CPU_CONF_WRT "WRT_PREDEFINE"
+#define CPU_CONF_LAZY "LAZY_PREDEFINE"
#define CPU_SHARE "/cpu.shares"
+#define MAX_PREDEFINED_TASKS 10
+#define CPU_TIMER_INTERVAL 30
+#define CPU_DEFAULT_PRI 0
+#define CPU_BACKGROUND_PRI 1
+#define CPU_CONTROL_PRI 10
+#define CPU_HIGHAPP_PRI -10
+
+static Ecore_Timer *cpu_predefined_timer = NULL;
+
+static inline int ioprio_set(int which, int who, int ioprio)
+{
+ return syscall(__NR_ioprio_set, which, who, ioprio);
+}
+
+enum
+{
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+enum
+{
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT 13
+
+enum cpu_control_type {
+ SET_NONE,
+ SET_DEFAUT,
+ SET_BOOTING,
+ SET_WRT,
+ SET_LAZY,
+};
+
+struct controltype {
+ int type;
+ pid_t pid;
+};
+
+struct predefined {
+ int num;
+ struct controltype control[MAX_PREDEFINED_TASKS];
+};
+
+struct predefined def_list = {0};
+
+static int check_predefined(const pid_t pid)
+{
+ int i = 0;
+
+ for (i = 0; i < def_list.num; i++) {
+ if (pid == def_list.control[i].pid)
+ return def_list.control[i].type;
+ }
+ return SET_NONE;
+}
static int cpu_move_cgroup(pid_t pid, char *path)
{
@@ -64,8 +131,36 @@ static int load_cpu_config(struct parse_result *result, void *user_data)
return RESOURCED_ERROR_NO_DATA;
if (!strcmp(result->name, CPU_CONF_PREDEFINE)) {
pid = find_pid_from_cmdline(result->value);
- if (pid > 0)
+ if (pid > 0) {
+ cpu_move_cgroup(pid, CPU_CONTROL_GROUP);
+ def_list.control[def_list.num].pid = pid;
+ def_list.control[def_list.num++].type = SET_DEFAUT;
+ } else {
+ _E("not found appname = %s", result->value);
+ }
+ } else if (!strcmp(result->name, CPU_CONF_BOOTING)) {
+ pid = find_pid_from_cmdline(result->value);
+ if (pid > 0) {
cpu_move_cgroup(pid, CPU_CONTROL_GROUP);
+ def_list.control[def_list.num].pid = pid;
+ def_list.control[def_list.num++].type = SET_BOOTING;
+ setpriority(PRIO_PROCESS, pid, CPU_CONTROL_PRI);
+ }
+ } else if (!strcmp(result->name, CPU_CONF_WRT)) {
+ pid = find_pid_from_cmdline(result->value);
+ if (pid > 0) {
+ cpu_move_cgroup(pid, CPU_CONTROL_GROUP);
+ def_list.control[def_list.num].pid = pid;
+ def_list.control[def_list.num++].type = SET_WRT;
+ setpriority(PRIO_PROCESS, pid, CPU_CONTROL_PRI);
+ ioprio_set(IOPRIO_WHO_PROCESS, pid, IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT);
+ }
+ } else if (!strcmp(result->name, CPU_CONF_LAZY)) {
+ pid = find_pid_from_cmdline(result->value);
+ if (pid > 0) {
+ def_list.control[def_list.num].pid = pid;
+ def_list.control[def_list.num++].type = SET_LAZY;
+ }
} else if (!strcmp(result->name, "BACKGROUND_CPU_SHARE")) {
value = atoi(result->value);
if (value)
@@ -89,8 +184,13 @@ static int cpu_service_launch(void *data)
static int cpu_foreground_state(void *data)
{
struct proc_status *p_data = (struct proc_status*)data;
+ int pri;
_D("cpu_foreground_state : pid = %d, appname = %s", p_data->pid, p_data->appid);
- cpu_move_cgroup(p_data->pid, CPU_DEFAULT_CGROUP);
+ pri = getpriority(PRIO_PROCESS, p_data->pid);
+ if (pri == -1 || pri > CPU_DEFAULT_PRI)
+ setpriority(PRIO_PGRP, p_data->pid, CPU_DEFAULT_PRI);
+ if (check_predefined(p_data->pid) != SET_DEFAUT)
+ cpu_move_cgroup(p_data->pid, CPU_DEFAULT_CGROUP);
return RESOURCED_ERROR_NONE;
}
@@ -98,10 +198,65 @@ static int cpu_background_state(void *data)
{
struct proc_status *p_data = (struct proc_status*)data;
_D("cpu_background_state : pid = %d, appname = %s", p_data->pid, p_data->appid);
+ setpriority(PRIO_PGRP, p_data->pid, CPU_BACKGROUND_PRI);
cpu_move_cgroup(p_data->pid, CPU_CONTROL_SERVICE_GROUP);
return RESOURCED_ERROR_NONE;
}
+static int cpu_prelaunch_state(void *data)
+{
+ struct proc_status *p_data = (struct proc_status*)data;
+ struct proc_process_info_t *ppi = p_data->ppi;
+ int i = 0;
+ GSList *iter = NULL;
+ if (!cpu_predefined_timer)
+ return RESOURCED_ERROR_NONE;
+ if (ppi->type & PROC_WEBAPP) {
+ for (i = 0; i < def_list.num; i++) {
+ if (def_list.control[i].type == SET_WRT) {
+ cpu_move_cgroup(def_list.control[i].pid, CPU_DEFAULT_CGROUP);
+ setpriority(PRIO_PGRP, def_list.control[i].pid, 0);
+ ioprio_set(IOPRIO_WHO_PROCESS, def_list.control[i].pid, IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT);
+ return RESOURCED_ERROR_NONE;
+ }
+ }
+ } else {
+ gslist_for_each_item(iter, ppi->pids) {
+ struct pid_info_t *pi = (struct pid_info_t *)(iter->data);
+ if (pi && pi->type == PROC_TYPE_GUI) {
+ if (check_predefined(pi->pid) == SET_BOOTING) {
+ cpu_move_cgroup(p_data->pid, CPU_DEFAULT_CGROUP);
+ setpriority(PRIO_PGRP, p_data->pid, 0);
+ return RESOURCED_ERROR_NONE;
+ }
+ }
+ }
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+static Eina_Bool cpu_predefined_cb(void *data)
+{
+ int i = 0;
+
+ for (i = 0; i < def_list.num; i++) {
+ if (def_list.control[i].type == SET_LAZY) {
+ cpu_move_cgroup(def_list.control[i].pid, CPU_CONTROL_GROUP);
+ } else if (def_list.control[i].type == SET_BOOTING) {
+ cpu_move_cgroup(def_list.control[i].pid, CPU_DEFAULT_CGROUP);
+ setpriority(PRIO_PROCESS, def_list.control[i].pid, 0);
+ } else if (def_list.control[i].type == SET_WRT) {
+ cpu_move_cgroup(def_list.control[i].pid, CPU_DEFAULT_CGROUP);
+ setpriority(PRIO_PROCESS, def_list.control[i].pid, 0);
+ ioprio_set(IOPRIO_WHO_PROCESS, def_list.control[i].pid, IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT);
+ }
+ }
+ ecore_timer_del(cpu_predefined_timer);
+ cpu_predefined_timer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+
+}
+
static int resourced_cpu_init(void *data)
{
int ret_code;
@@ -113,10 +268,14 @@ static int resourced_cpu_init(void *data)
ret_value_msg_if(ret_code < 0, ret_code, "create service cgroup failed\n");
config_parse(CPU_CONF_FILE, load_cpu_config, NULL);
+ if (def_list.num)
+ cpu_predefined_timer =
+ ecore_timer_add(CPU_TIMER_INTERVAL, cpu_predefined_cb, NULL);
register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, cpu_service_launch);
register_notifier(RESOURCED_NOTIFIER_APP_RESUME, cpu_foreground_state);
register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, cpu_foreground_state);
register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, cpu_background_state);
+ register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, cpu_prelaunch_state);
return RESOURCED_ERROR_NONE;
}
@@ -126,6 +285,7 @@ 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_APP_BACKGRD, cpu_background_state);
+ unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, cpu_prelaunch_state);
return RESOURCED_ERROR_NONE;
}
diff --git a/src/cpu/cpu.conf b/src/cpu/cpu.conf
index 609c4648..4e9e3861 100644
--- a/src/cpu/cpu.conf
+++ b/src/cpu/cpu.conf
@@ -1,6 +1,10 @@
[CONTROL]
# predefined process list
+LAZY_PREDEFINE=net-config
PREDEFINE=indicator
-PREDEFINE=net-config
+BOOTING_PREDEFINE=quickpanel
+WRT_PREDEFINE=wrt_launchpad_daemon
+BOOTING_PREDEFINE=volume
+BOOTING_PREDEFINE=nvitemd
BACKGROUND_CPU_SHARE=50
SERVICE_CPU_SHARE=128
diff --git a/src/cpu/logging-cpu.c b/src/cpu/logging-cpu.c
index bdb7c1a8..c6ae0784 100644
--- a/src/cpu/logging-cpu.c
+++ b/src/cpu/logging-cpu.c
@@ -55,7 +55,7 @@
#define CPU_MAX_INTERVAL 20*60 /* 5 min */
#define CPU_INIT_INTERVAL 20*60 /* 3 min */
-#define CPU_FOREGRD_INTERVAL 3*60 /* 1 min */
+#define CPU_FOREGRD_INTERVAL 2 /* 1 min */
#define CPU_BACKGRD_INTERVAL 10*60 /* 2 min */
#define CPU_BACKGRD_OLD_INTERVAL 15*60 /* 5 min */
@@ -64,6 +64,8 @@ struct logging_cpu_info {
unsigned long stime;
unsigned long last_utime;
unsigned long last_stime;
+ unsigned long last_commit_utime;
+ unsigned long last_commit_stime;
bool last_commited;
time_t last_log_time;
time_t log_interval;
@@ -147,6 +149,8 @@ static int init_cpu_info(void **pl, int pid, int oom, time_t now)
info->stime = 0;
info->last_utime = 0;
info->last_stime = 0;
+ info->last_commit_utime = 0;
+ info->last_commit_stime = 0;
info->last_log_time = now;
info->last_commited = false;
@@ -215,13 +219,18 @@ static int write_cpu_info(char *name, struct logging_infos *infos,
if (!infos->running && ci->last_commited)
return RESOURCED_ERROR_NONE;
+ if (ci->last_commit_utime == ci->utime &&
+ ci->last_commit_stime == ci->stime)
+ return RESOURCED_ERROR_NONE;
+
sd_journal_send("NAME=cpu",
"TIME=%ld", ci->last_log_time,
"PNAME=%s", name,
"UTIME=%ld", ci->utime,
"STIME=%ld", ci->stime,
NULL);
-
+ ci->last_commit_utime = ci->utime;
+ ci->last_commit_stime = ci->stime;
ci->last_commited = true;
return RESOURCED_ERROR_NONE;
diff --git a/src/logging/include/logging.h b/src/logging/include/logging.h
index e64a2230..7e27a87d 100644
--- a/src/logging/include/logging.h
+++ b/src/logging/include/logging.h
@@ -42,5 +42,4 @@ struct logging_info_ops {
int register_logging_subsystem(const char *name, struct logging_info_ops *ops);
int update_commit_interval(const char *name, time_t commit_interval);
-int get_pss(pid_t pid, unsigned *pss, unsigned *uss);
#endif /*__LOGGING_H__*/
diff --git a/src/logging/logging.c b/src/logging/logging.c
index fd81f1c9..166a0513 100644
--- a/src/logging/logging.c
+++ b/src/logging/logging.c
@@ -54,11 +54,12 @@
#define WRITE_INFO_MAX 10
#define MAX_PROC_LIST 200
-#define WEBPROCESS_NAME "WebProcess"
+#define WEBPROCESS_NAME "/usr/bin/WebProcess"
+#define WEBPROCESS_NAME_LEN 19
#define MAX_PROC_ITEM 200
#define INC_PROC_ITEM 10
#define COMMIT_INTERVAL 10*60 /* 10 min */
-#define LOGGING_PTIORITY -20
+#define LOGGING_PTIORITY 20
#define SIGNAL_LOGGING_INIT "LoggingInit"
#define SIGNAL_LOGGING_GET "LoggingGet"
@@ -84,6 +85,8 @@ static pthread_mutex_t logging_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t proc_list_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t logging_cond = PTHREAD_COND_INITIALIZER;
+static void broadcast_logging_data_updated_signal(void);
+
static int init_logging_infos(struct logging_infos *info, const char *key,
pid_t pid, int oom, time_t now)
{
@@ -139,9 +142,9 @@ static void insert_hash_table(char *key, pid_t pid, int oom)
struct logging_infos *info;
void **stats;
char *name;
- time_t now;
+ struct timespec ts;
- now = time(NULL);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
name = malloc(strlen(key) + 1);
@@ -168,10 +171,10 @@ static void insert_hash_table(char *key, pid_t pid, int oom)
}
info->stats = stats;
- init_logging_infos(info, name, pid, oom, now);
+ init_logging_infos(info, name, pid, oom, ts.tv_sec);
g_hash_table_insert(logging_proc_list, (gpointer) name, (gpointer) info);
- update_logging_infos(info, now, true);
+ update_logging_infos(info, ts.tv_sec, true);
return;
}
@@ -227,6 +230,9 @@ static int write_logging_subsys_info(struct logging_sub_sys *pss, int sindex,
write_journal(pss, sindex);
pss->last_commit = now;
+
+ broadcast_logging_data_updated_signal();
+
return RESOURCED_ERROR_NONE;
}
@@ -235,16 +241,16 @@ static int write_logging_infos(bool force)
{
int i;
int ret;
- time_t now;
+ struct timespec ts;
- now = time(NULL);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
for (i = 0; i < logging_ss_list->len; i++) {
struct logging_sub_sys *ss = &g_array_index(logging_ss_list,
struct logging_sub_sys, i);
- ret = write_logging_subsys_info(ss, i, now, force);
+ ret = write_logging_subsys_info(ss, i, ts.tv_sec, force);
if (ret != RESOURCED_ERROR_NONE) {
- _E("write logging at %lu", now);
+ _E("write logging at %lu", ts.tv_sec);
/* not return error, just continue updating */
}
}
@@ -256,7 +262,7 @@ int register_logging_subsystem(const char*name, struct logging_info_ops *ops)
{
struct logging_sub_sys ss;
char *ss_name;
- time_t now;
+ struct timespec ts;
ss_name = malloc(strlen(name)+1);
@@ -265,12 +271,12 @@ int register_logging_subsystem(const char*name, struct logging_info_ops *ops)
return RESOURCED_ERROR_FAIL;
}
- now = time(NULL);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
strcpy(ss_name, name);
ss.name = ss_name;
ss.commit_interval = COMMIT_INTERVAL;
- ss.last_commit = now;
+ ss.last_commit = ts.tv_sec;
ss.ops = ops;
g_array_append_val(logging_ss_list, ss);
@@ -299,21 +305,7 @@ int update_commit_interval(const char *name, time_t commit_interval)
static inline int is_webprocess(char *name)
{
- return !strcmp(name, WEBPROCESS_NAME);
-}
-
-static int rename_webprocess(pid_t pgid, char *name)
-{
- char webui_name[PROC_NAME_MAX];
- int ret;
-
- if ((ret = proc_get_cmdline(pgid, webui_name)) != RESOURCED_ERROR_NONE)
- return RESOURCED_ERROR_FAIL;
-
- strcat(name, ".");
- strcat(name, webui_name);
-
- return RESOURCED_ERROR_NONE;
+ return !strncmp(name, WEBPROCESS_NAME, WEBPROCESS_NAME_LEN);
}
static int get_cmdline(pid_t pid, char *cmdline)
@@ -335,6 +327,20 @@ static int get_cmdline(pid_t pid, char *cmdline)
return RESOURCED_ERROR_NONE;
}
+static int rename_webprocess(pid_t pgid, char *name)
+{
+ char webui_name[PROC_NAME_MAX];
+ int ret;
+
+ if ((ret = get_cmdline(pgid, webui_name)) != RESOURCED_ERROR_NONE)
+ return RESOURCED_ERROR_FAIL;
+
+ strcat(name, ":");
+ strcat(name, webui_name);
+
+ return RESOURCED_ERROR_NONE;
+}
+
static void insert_proc_list(pid_t pid, pid_t pgid, int oom)
{
int ret = RESOURCED_ERROR_NONE;
@@ -460,14 +466,14 @@ static void update_proc_list(void)
{
GHashTableIter iter;
gpointer key, value;
- time_t now;
struct logging_infos *infos;
+ struct timespec ts;
int ret;
if (need_to_update)
update_proc_state();
- now = time(NULL);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
g_hash_table_iter_init(&iter, logging_proc_list);
@@ -490,7 +496,7 @@ static void update_proc_list(void)
infos = (struct logging_infos *)value;
if (infos->running)
- update_logging_infos(infos, now, false);
+ update_logging_infos(infos, ts.tv_sec, false);
ret = pthread_mutex_unlock(&proc_list_mutex);
if (ret) {
_E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
@@ -737,7 +743,6 @@ static void logging_get_edbus_signal_handler(void *data, DBusMessage *msg)
}
write_logging_infos(true);
_D("logging_get_edbus_signal_handler");
- broadcast_logging_data_updated_signal();
}
static int logging_init(void)
@@ -771,11 +776,11 @@ static int logging_init(void)
register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_INIT,
- (void *)logging_init_booting_done_edbus_signal_handler);
+ (void *)logging_init_booting_done_edbus_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_GET,
- (void *)logging_get_edbus_signal_handler);
+ (void *)logging_get_edbus_signal_handler, NULL);
return RESOURCED_ERROR_NONE;
}
diff --git a/src/memory/helper.c b/src/memory/helper.c
new file mode 100644
index 00000000..614ba9cc
--- /dev/null
+++ b/src/memory/helper.c
@@ -0,0 +1,542 @@
+/*
+ * 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 smap-helper.c
+ *
+ * @desc proc/<pid>/smaps file helper functions
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <linux/limits.h>
+
+#include <ctype.h>
+#include <stddef.h>
+
+#include <dirent.h>
+#include <sys/utsname.h>
+#include <stdbool.h>
+
+#include "trace.h"
+#include "logging.h"
+#include "file-helper.h"
+#include "edbus-handler.h"
+
+#include "helper.h"
+
+/* Memory info (/proc/meminfo) */
+#define MEMINFO_PATH "/proc/meminfo"
+#define MEMINFO_TOTAL "MemTotal:"
+#define MEMINFO_FREE "MemFree:"
+#define MEMINFO_AVAILABLE "MemAvailable:"
+#define MEMINFO_CACHED "Cached:"
+#define KBtoMB(x) ((x)>>10)
+
+static struct mapinfo *mi;
+static struct mapinfo *maps;
+static int smaps_initialized;
+
+bool starts_with(const char *pref, const char *str, const size_t size)
+{
+ return strncmp(pref, str, size) == 0;
+}
+
+static int read_mapinfo(char **smaps)
+{
+ char *line;
+ unsigned tmp;
+ unsigned read_lines = 0;
+ int ignore = 0;
+ static unsigned ignored_lines;
+
+ mi->size = 0;
+ mi->rss = 0;
+ mi->pss = 0;
+ mi->shared_clean = 0;
+ mi->shared_dirty = 0;
+ mi->private_clean = 0;
+ mi->private_dirty = 0;
+
+ while ((line = cgets(smaps)) != NULL) {
+ tmp = 0;
+
+ /*
+ * Fast ignore lines, when we know how much
+ * we can ignore to the end.
+ */
+ if (ignore > 0 && ignored_lines > 0) {
+ ignore--;
+ continue;
+ }
+
+ if (starts_with("Size: ", line, 6)) {
+ if (sscanf(line, "Size: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->size += tmp;
+ continue;
+ }
+ } else if (starts_with("Rss: ", line, 5)) {
+ if (sscanf(line, "Rss: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->rss += tmp;
+ continue;
+ }
+ } else if (starts_with("Pss: ", line, 5)) {
+ if (sscanf(line, "Pss: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->pss += tmp;
+ continue;
+ }
+ } else if (starts_with("Shared_Clean: ", line, 14)) {
+ if (sscanf(line, "Shared_Clean: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->shared_clean += tmp;
+ continue;
+ }
+ } else if (starts_with("Shared_Dirty: ", line, 14)) {
+ if (sscanf(line, "Shared_Dirty: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->shared_dirty += tmp;
+ continue;
+ }
+ } else if (starts_with("Private_Clean: ", line, 15)) {
+ if (sscanf(line, "Private_Clean: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->private_clean += tmp;
+ continue;
+ }
+ } else if (starts_with("Private_Dirty: ", line, 15)) {
+ if (sscanf(line, "Private_Dirty: %d kB", &tmp) != 1) {
+ return RESOURCED_ERROR_FAIL;
+ } else {
+ mi->private_dirty += tmp;
+ /*
+ * We just read last interesting for us field.
+ * Now we can ignore the rest of current block.
+ */
+ ignore = ignored_lines;
+ continue;
+ }
+ } else {
+ /*
+ * This calculates how many lines from the last field read
+ * we can safety ignore.
+ * The 'header line' is also counted, later we remove it
+ * because it is the first one and we don't want to overlap
+ * later when reading.
+ *
+ * The last line in smaps single block starts with 'VmFlags: '
+ * when occurred we know the amount of fields that we can ignore
+ * in smaps block.
+ * We count that only once per resourced running. (depends on
+ * kernel version)
+ *
+ * This won't work if we want to omit some fields in the middle
+ * of smaps block.
+ */
+
+ read_lines++; /* not handled before, so count */
+
+ if (ignored_lines == 0) /* make it only once */
+ if (starts_with("VmFlags: ", line, 9))
+ ignored_lines = read_lines-1;
+
+ continue; /* ignore that line anyways */
+ }
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+
+static void init_maps(void)
+{
+ maps->size = 0;
+ maps->rss = 0;
+ maps->pss = 0;
+ maps->shared_clean = 0;
+ maps->shared_dirty = 0;
+ maps->private_clean = 0;
+ maps->private_dirty = 0;
+}
+
+static int load_maps(int pid)
+{
+ char *smaps, *start;
+ char tmp[128];
+
+ sprintf(tmp, "/proc/%d/smaps", pid);
+ smaps = cread(tmp);
+ if (smaps == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ start = smaps;
+ init_maps();
+
+ read_mapinfo(&smaps);
+
+ maps->size = mi->size;
+ maps->rss = mi->rss;
+ maps->pss = mi->pss;
+ maps->shared_clean = mi->shared_clean;
+ maps->shared_dirty = mi->shared_dirty;
+ maps->private_clean = mi->private_clean;
+ maps->private_dirty = mi->private_dirty;
+
+ _D("load_maps: %d %d %d %d %d", maps->size, maps->pss,
+ maps->rss, maps->shared_dirty, maps->private_dirty);
+
+ if (start)
+ free(start);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+
+static int allocate_memory(void)
+{
+ if (smaps_initialized > 0) {
+ _D("smaps helper already initialized");
+ return RESOURCED_ERROR_NONE;
+ }
+
+ maps = (struct mapinfo *)malloc(sizeof(struct mapinfo));
+
+ if (!maps) {
+ _E("fail to allocate mapinfo\n");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ mi = malloc(sizeof(struct mapinfo));
+ if (mi == NULL) {
+ _E("malloc failed for mapinfo");
+ free(maps);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ smaps_initialized++;
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int smaps_helper_get_meminfo(pid_t pid, struct mapinfo **meminfo)
+{
+ int ret;
+
+ ret = load_maps(pid);
+ if (ret != RESOURCED_ERROR_NONE)
+ init_maps();
+ else
+ *meminfo = maps;
+ return ret;
+}
+
+static int load_statm(int pid)
+{
+ FILE *fp;
+ char tmp[128];
+
+ sprintf(tmp, "/proc/%d/statm", pid);
+ fp = fopen(tmp, "r");
+ if (fp == NULL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (fscanf(fp, "%d %d", &mi->size, &mi->rss) < 1) {
+ fclose(fp);
+ return RESOURCED_ERROR_FAIL;
+ }
+ fclose(fp);
+
+ /* Convert from pages to Kb */
+ maps->size = mi->size*4;
+ maps->rss = mi->rss*4;
+
+ _D("load_statm: %d %d", maps->size, maps->rss);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+int smaps_helper_get_vmsize(pid_t pid, unsigned *vmsize, unsigned *vmrss)
+{
+ int ret;
+
+ ret = load_maps(pid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ *vmsize = 0;
+ *vmrss = 0;
+ } else {
+ *vmsize = maps->size;
+ *vmrss = maps->rss;
+ }
+
+ return ret;
+}
+
+int statm_helper_get_vmsize(pid_t pid, unsigned *vmsize, unsigned *vmrss)
+{
+ int ret;
+
+ ret = load_statm(pid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ *vmsize = 0;
+ *vmrss = 0;
+ } else {
+ *vmsize = maps->size;
+ *vmrss = maps->rss;
+ }
+
+ return ret;
+}
+
+int smaps_helper_get_shared(pid_t pid, unsigned *shared_clean,
+ unsigned *shared_dirty)
+{
+ int ret;
+
+ ret = load_maps(pid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ *shared_clean = 0;
+ *shared_dirty = 0;
+ } else {
+ *shared_clean = maps->shared_clean;
+ *shared_dirty = maps->private_dirty;
+ }
+
+ return ret;
+}
+
+int smaps_helper_get_pss(pid_t pid, unsigned *pss, unsigned *uss)
+{
+ int ret;
+
+ ret = load_maps(pid);
+ if (ret != RESOURCED_ERROR_NONE) {
+ *pss = 0;
+ *uss = 0;
+ } else {
+ *pss = maps->pss;
+ *uss = maps->private_clean + maps->private_dirty;
+ }
+
+ return ret;
+}
+
+int smaps_helper_init(void)
+{
+ int ret;
+
+ ret = allocate_memory();
+
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("allocate structures failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ smaps_initialized--;
+ return RESOURCED_ERROR_NONE;
+}
+
+void smaps_helper_free(void)
+{
+ free(maps);
+ free(mi);
+}
+
+struct memory_info {
+ unsigned int total;
+ unsigned int free;
+ unsigned int available;
+ unsigned int cached;
+};
+
+static int read_mem_info(char *buf, char *type, unsigned int *val)
+{
+ char *idx;
+
+ if (!type || !buf || !val)
+ return -EINVAL;
+
+ idx = strstr(buf, type);
+ if (!idx)
+ return -ENOENT;
+
+ idx += strlen(type);
+
+ while (*idx < '0' || *idx > '9')
+ idx++;
+
+ *val = strtoul(idx, NULL, 10);
+
+ return 0;
+}
+
+static unsigned int get_mem_info(struct memory_info *info)
+{
+ char buf[PATH_MAX];
+ size_t len;
+ FILE *fp;
+ int ret;
+
+ if (!info)
+ return -EINVAL;
+
+ fp = fopen(MEMINFO_PATH, "r");
+ if (!fp) {
+ ret = -errno;
+ _E("%s open failed(errno:%d)", MEMINFO_PATH, ret);
+ return ret;
+ }
+
+ len = sizeof(buf);
+ while (fgets(buf, len, fp) != NULL) {
+ if (read_mem_info(buf, MEMINFO_TOTAL, &(info->total)) == 0)
+ continue;
+ if (read_mem_info(buf, MEMINFO_FREE, &(info->free)) == 0)
+ continue;
+ if (read_mem_info(buf, MEMINFO_AVAILABLE, &(info->available)) == 0)
+ continue;
+ if (read_mem_info(buf, MEMINFO_CACHED, &(info->cached)) == 0)
+ continue;
+ }
+
+ fclose(fp);
+
+ if (info->available == 0)
+ info->available = info->cached + info->free;
+
+ return 0;
+}
+
+unsigned int get_available(void)
+{
+ int ret;
+ struct memory_info info = {0,};
+ int available = 0;
+
+ ret = get_mem_info(&info);
+ if (ret < 0) {
+ _E("Failed to get mem info (%d)", ret);
+ return available;
+ }
+
+ available = info.available;
+
+ return KBtoMB(available);
+}
+
+unsigned int get_mem_usage(void)
+{
+ int ret;
+ struct memory_info info = {0,};
+ int usage;
+
+ ret = get_mem_info(&info);
+ if (ret < 0) {
+ _E("Failed to get mem info (%d)", ret);
+ return ret;
+ }
+
+ usage = info.total - info.available;
+
+ return KBtoMB(usage);
+}
+
+#include <bundle.h>
+#include <bundle_internal.h>
+
+#define EVENT_SYSTEM_PATH "/tizen/system/event"
+#define EVENT_SYSTEM_IFACE "tizen.system.event"
+#define EVENT_SYSTEM_SIGNAL "low_memory"
+
+#define EVT_KEY_LOW_MEMORY "low_memory"
+#define EVT_VAL_MEMORY_NORMAL "normal"
+#define EVT_VAL_MEMORY_SOFT_WARNING "soft_warning"
+#define EVT_VAL_MEMORY_HARD_WARNING "hard_warning"
+
+#define BUF_MAX 128
+
+void memory_level_send_system_event(int lv)
+{
+ bundle *b;
+ bundle_raw *raw = NULL;
+ int raw_len;
+ const char *str;
+ char *param[3];
+ char trusted[BUF_MAX];
+ char len[BUF_MAX];
+ int ret;
+
+ switch (lv) {
+ case MEMORY_LEVEL_NORMAL:
+ str = EVT_VAL_MEMORY_NORMAL;
+ break;
+ case MEMORY_LEVEL_LOW:
+ str = EVT_VAL_MEMORY_SOFT_WARNING;
+ break;
+ case MEMORY_LEVEL_CRITICAL:
+ str = EVT_VAL_MEMORY_HARD_WARNING;
+ break;
+ default:
+ _E("Invalid state");
+ return;
+ }
+
+ _I("Send event system signal (%s)", str);
+
+ b = bundle_create();
+ if (!b) {
+ _E("Failed to create bundle");
+ return;
+ }
+
+ bundle_add_str(b, EVT_KEY_LOW_MEMORY, str);
+ bundle_encode(b, &raw, &raw_len);
+
+ snprintf(trusted, sizeof(trusted), "%d", 0); /* 0 == FALSE */
+ param[0] = trusted;
+ snprintf(len, sizeof(len), "%d", raw_len);
+ param[1] = len;
+ param[2] = (char *)raw;
+
+ ret = broadcast_edbus_signal_str(
+ EVENT_SYSTEM_PATH,
+ EVENT_SYSTEM_IFACE,
+ EVENT_SYSTEM_SIGNAL,
+ "bus", param);
+ if (ret < 0)
+ _E("Failed to send signal of memory state to event-system");
+
+ bundle_free_encoded_rawdata(&raw);
+ bundle_free(b);
+}
diff --git a/src/memory/helper.h b/src/memory/helper.h
new file mode 100644
index 00000000..ef26299c
--- /dev/null
+++ b/src/memory/helper.h
@@ -0,0 +1,58 @@
+/*
+ * 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 smaps-helper.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef SRC_MEMORY_SMAPS_HELPER_H_
+#define SRC_MEMORY_SMAPS_HELPER_H_
+
+struct mapinfo {
+ unsigned size;
+ unsigned rss;
+ unsigned pss;
+ unsigned shared_clean;
+ unsigned shared_dirty;
+ unsigned private_clean;
+ unsigned private_dirty;
+};
+
+int smaps_helper_get_meminfo(pid_t pid, struct mapinfo **meminfo);
+int smaps_helper_get_pss(pid_t pid, unsigned *pss, unsigned *uss);
+int smaps_helper_get_shared(pid_t pid, unsigned *shared_clean, unsigned *shared_dirty);
+int smaps_helper_get_vmsize(pid_t pid, unsigned *vmsize, unsigned *vmrss);
+int statm_helper_get_vmsize(pid_t pid, unsigned *vmsize, unsigned *vmrss);
+int smaps_helper_init(void);
+void smaps_helper_free(void);
+
+unsigned int get_available(void);
+unsigned int get_mem_usage(void);
+
+enum memory_level {
+ MEMORY_LEVEL_NORMAL,
+ MEMORY_LEVEL_LOW,
+ MEMORY_LEVEL_CRITICAL,
+};
+
+void memory_level_send_system_event(int lv);
+
+#endif /* SRC_MEMORY_SMAPS_HELPER_H_ */
diff --git a/src/memory/logging-memory.c b/src/memory/logging-memory.c
index 532d6712..8fca2726 100644
--- a/src/memory/logging-memory.c
+++ b/src/memory/logging-memory.c
@@ -49,6 +49,7 @@
#include "macro.h"
#include "proc-process.h"
#include "logging.h"
+#include "smaps-helper.h"
#define MEM_NAME "memory"
#define MEM_COMMIT_INTERVAL 30*60 /* 30 min */
@@ -71,165 +72,6 @@ struct logging_memory_info {
pid_t current_pid;
};
-struct mapinfo {
- unsigned size;
- unsigned rss;
- unsigned pss;
- unsigned shared_clean;
- unsigned shared_dirty;
- unsigned private_clean;
- unsigned private_dirty;
-};
-
-static int ignore_smaps_field;
-static struct mapinfo *mi;
-static struct mapinfo *maps;
-
-static void check_kernel_version(void)
-{
- struct utsname buf;
- int ret;
-
- ret = uname(&buf);
-
- if (ret)
- return;
-
- if (buf.release[0] == '3') {
- char *pch;
- char str[3];
- int sub_version;
- pch = strstr(buf.release, ".");
- strncpy(str, pch+1, 2);
- sub_version = atoi(str);
-
- if (sub_version >= 10)
- ignore_smaps_field = 8; /* Referenced, Anonymous, AnonHugePages,
- Swap, KernelPageSize, MMUPageSize,
- Locked, VmFlags */
-
- else
- ignore_smaps_field = 7; /* Referenced, Anonymous, AnonHugePages,
- Swap, KernelPageSize, MMUPageSize,
- Locked */
- } else {
- ignore_smaps_field = 4; /* Referenced, Swap, KernelPageSize,
- MMUPageSize */
- }
-}
-
-
-/* 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so
- * 012345678901234567890123456789012345678901234567890123456789
- * 0 1 2 3 4 5
- */
-
-static int read_mapinfo(char** smaps, int rest_line)
-{
- char* line;
- int len;
-
- if ((line = cgets(smaps)) == 0)
- return RESOURCED_ERROR_FAIL;
-
- len = strlen(line);
- if (len < 1) {
- _E("line is less than 1");
- return RESOURCED_ERROR_FAIL;
- }
-
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Size: %d kB", &mi->size) != 1)
- goto oops;
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Rss: %d kB", &mi->rss) != 1)
- goto oops;
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Pss: %d kB", &mi->pss) == 1)
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1)
- goto oops;
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1)
- goto oops;
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1)
- goto oops;
- if ((line = cgets(smaps)) == 0)
- goto oops;
- if (sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1)
- goto oops;
-
- while (rest_line-- && cgets(smaps))
- ;
-
- return RESOURCED_ERROR_NONE;
- oops:
- _E("mi get error\n");
- return RESOURCED_ERROR_FAIL;
-}
-
-static void init_maps()
-{
- maps->size = 0;
- maps->rss = 0;
- maps->pss = 0;
- maps->shared_clean = 0;
- maps->shared_dirty = 0;
- maps->private_clean = 0;
- maps->private_dirty = 0;
-}
-
-static int load_maps(int pid)
-{
- char* smaps, *start;
- char tmp[128];
-
- sprintf(tmp, "/proc/%d/smaps", pid);
- smaps = cread(tmp);
- if (smaps == NULL)
- return RESOURCED_ERROR_FAIL;
-
- start = smaps;
- init_maps();
-
- while (read_mapinfo(&smaps, ignore_smaps_field)
- == RESOURCED_ERROR_NONE) {
- maps->size += mi->size;
- maps->rss += mi->rss;
- maps->pss += mi->pss;
- maps->shared_clean += mi->shared_clean;
- maps->shared_dirty += mi->shared_dirty;
- maps->private_clean += mi->private_clean;
- maps->private_dirty += mi->private_dirty;
- }
-
- if(start)
- free(start);
- return RESOURCED_ERROR_NONE;
-}
-
-int get_pss(pid_t pid, unsigned *pss, unsigned *uss)
-{
- int ret;
- ret = load_maps(pid);
- if (ret != RESOURCED_ERROR_NONE) {
- *pss = 0;
- *uss = 0;
- } else {
- *pss = maps->pss;
- *uss = maps->private_clean + maps->private_dirty;
- }
-
- return ret;
-}
-
static void update_log_interval(struct logging_memory_info *loginfo, int oom,
int always)
{
@@ -296,7 +138,7 @@ static int update_memory_info(void *pl, pid_t pid, int oom,
if (now < loginfo->last_log_time + loginfo->log_interval)
return ret;
- ret = get_pss(pid, &pss, &uss);
+ ret = smaps_helper_get_pss(pid, &pss, &uss);
if (ret != RESOURCED_ERROR_NONE)
return ret;
@@ -346,52 +188,25 @@ static struct logging_info_ops memory_info_ops = {
.init = init_memory_info,
};
-static int allocate_memory(void)
-{
- maps = (struct mapinfo *)malloc(sizeof(struct mapinfo));
-
- if (!maps) {
- _E("fail to allocate mapinfo\n");
- return RESOURCED_ERROR_FAIL;
- }
-
- mi = malloc(sizeof(struct mapinfo));
- if (mi == NULL) {
- _E("malloc failed for mapinfo");
- free(maps);
- return RESOURCED_ERROR_FAIL;
- }
- return RESOURCED_ERROR_NONE;
-}
-
-static void free_memory(void)
-{
- free(maps);
- free(mi);
-}
-
static int logging_memory_init(void *data)
{
int ret;
- check_kernel_version();
-
- ret = allocate_memory();
-
+ ret = smaps_helper_init();
if (ret != RESOURCED_ERROR_NONE) {
- _E("allocate structures failed");
- return RESOURCED_ERROR_FAIL;
+ _E("smaps helper failed");
+ return RESOURCED_ERROR_FAIL;
}
ret = register_logging_subsystem(MEM_NAME, &memory_info_ops);
if(ret != RESOURCED_ERROR_NONE) {
_E("register logging subsystem failed");
- free_memory();
+ smaps_helper_free();
return RESOURCED_ERROR_FAIL;
}
ret = update_commit_interval(MEM_NAME, MEM_COMMIT_INTERVAL);
if(ret != RESOURCED_ERROR_NONE) {
_E("update commit interval logging subsystem failed");
- free_memory();
+ smaps_helper_free();
return RESOURCED_ERROR_FAIL;
}
@@ -402,7 +217,7 @@ static int logging_memory_init(void *data)
static int logging_memory_exit(void *data)
{
_D("logging memory finalize");
- free_memory();
+ smaps_helper_free();
return RESOURCED_ERROR_NONE;
}
diff --git a/src/memory/lowmem-dbus.c b/src/memory/lowmem-dbus.c
index d2626257..4fa5828a 100644
--- a/src/memory/lowmem-dbus.c
+++ b/src/memory/lowmem-dbus.c
@@ -32,6 +32,7 @@
#include "edbus-handler.h"
#include "resourced.h"
#include "macro.h"
+#include "memcontrol.h"
#define SIGNAL_NAME_OOM_SET_THRESHOLD "SetThreshold"
#define SIGNAL_NAME_OOM_SET_LEAVE_THRESHOLD "SetLeaveThreshold"
@@ -59,7 +60,7 @@ static void lowmem_dbus_oom_set_threshold(void *data, DBusMessage *msg)
return;
}
- set_threshold(level, thres);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, level, thres);
}
static void lowmem_dbus_oom_set_leave_threshold(void *data, DBusMessage *msg)
@@ -84,7 +85,7 @@ static void lowmem_dbus_oom_set_leave_threshold(void *data, DBusMessage *msg)
return;
}
- set_leave_threshold(thres);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, thres);
}
static void lowmem_dbus_oom_trigger(void *data, DBusMessage *msg)
@@ -107,22 +108,22 @@ static void lowmem_dbus_oom_trigger(void *data, DBusMessage *msg)
if (launching)
flags |= OOM_NOMEMORY_CHECK;
- change_memory_state(MEMNOTIFY_LOW, 1);
- lowmem_oom_killer_cb(MEMCG_MEMORY, flags);
+ change_memory_state(LOWMEM_LOW, 1);
+ lowmem_memory_oom_killer(flags);
_D("flags = %d", flags);
- change_memory_state(MEMNOTIFY_NORMAL, 0);
+ change_memory_state(LOWMEM_NORMAL, 0);
}
void lowmem_dbus_init(void)
{
register_edbus_signal_handler(RESOURCED_PATH_OOM, RESOURCED_INTERFACE_OOM,
SIGNAL_NAME_OOM_SET_THRESHOLD,
- lowmem_dbus_oom_set_threshold);
+ lowmem_dbus_oom_set_threshold, NULL);
register_edbus_signal_handler(RESOURCED_PATH_OOM, RESOURCED_INTERFACE_OOM,
SIGNAL_NAME_OOM_SET_LEAVE_THRESHOLD,
- lowmem_dbus_oom_set_leave_threshold);
+ lowmem_dbus_oom_set_leave_threshold, NULL);
register_edbus_signal_handler(RESOURCED_PATH_OOM, RESOURCED_INTERFACE_OOM,
SIGNAL_NAME_OOM_TRIGGER,
- lowmem_dbus_oom_trigger);
+ lowmem_dbus_oom_trigger, NULL);
}
diff --git a/src/memory/lowmem-handler.c b/src/memory/lowmem-handler.c
index 6dd6466c..200b6975 100644
--- a/src/memory/lowmem-handler.c
+++ b/src/memory/lowmem-handler.c
@@ -26,6 +26,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <limits.h>
@@ -46,88 +47,32 @@
#include "cgroup.h"
#include "proc-main.h"
#include "lowmem-handler.h"
-#include "proc-process.h"
#include "swap-common.h"
+#include "proc-process.h"
#include "lowmem-common.h"
#include "resourced.h"
#include "macro.h"
#include "module.h"
#include "notifier.h"
+#include "helper.h"
-enum {
- MEMGC_OOM_NORMAL,
- MEMGC_OOM_SOFTSWAP,
- MEMGC_OOM_WARNING,
- MEMGC_OOM_HIGH,
- MEMGC_OOM_CRITICAL,
-};
-
-enum {
- MEMGC_GROUP_FOREGROUND,
- MEMGC_GROUP_BACKGROUND,
-};
-
-enum {
- MEM_SWAP_OFF,
- MEM_SWAP_ENABLE,
- MEM_SWAP_DECREASE,
- MEM_SWAP_INCREASE,
-};
-
-#define MEM_SOFTSWAP_ENABLE 1
-#define MEMCG_GROUP_MAX 2
-
-#define MEMINFO_PATH "/proc/meminfo"
-#define MEMCG_PATH "/sys/fs/cgroup/memory"
-#define VICTIM_TASK "/sys/class/lowmemnotify/victims"
-#define SET_LEAVE_THRESHOLD "/sys/class/lowmemnotify/leave_threshold"
-#define SET_CGROUP_LEAVE_THRESHOLD "/sys/class/lowmemnotify/cgroup_leave_threshold"
-#define SET_THRESHOLD_LV1 "/sys/class/lowmemnotify/threshold_level1"
-#define SET_THRESHOLD_LV2 "/sys/class/lowmemnotify/threshold_level2"
-#define SET_THRESHOLD_RECLAIM "/sys/class/lowmemnotify/threshold_reclaim"
-
-#define MEMPS_LOG_FILE "/var/log/memps"
+#define DEV_MEMNOTIFY "/dev/memnotify"
+#define VICTIM_TASK "/sys/class/memnotify/victims"
+#define SET_THRESHOLD_LV1 "/sys/class/memnotify/threshold_lv1"
+#define SET_THRESHOLD_LV2 "/sys/class/memnotify/threshold_lv2"
-#define DELETE_SM "sh -c "PREFIX"/bin/delete.sm"
+#define MEMPS_LOG_FILE "/var/log/memps"
#define MEMPS_EXEC_PATH "usr/bin/memps"
-
-#define _SYS_RES_CLEANUP "RES_CLEANUP"
-
-#define BtoMB(x) ((x) / 1024 / 1024)
-#define MBtoB(x) (x<<20)
-
-#define MEMCG_FOREGROUND_LIMIT_RATIO 0.6
-#define MEMCG_BACKGROUND_LIMIT_RATIO 0.7
-
-#define MEMCG_FOREGROUND_MIN_LIMIT MBtoB(400)
-#define MEMCG_BACKGROUND_MIN_LIMIT UINT_MAX
-
-/* threshold lv 1 : wakeup softswapd */
-#define MEMCG_TRHES_SOFTSWAP_RATIO 0.75
-
-/* threshold lv 2 : lowmem warning */
-#define MEMCG_THRES_WARNING_RATIO 0.92
-
-/* threshold lv 3 : victim kill */
-#define MEMCG_THRES_OOM_RATIO 0.96
-
-/* leave threshold */
-#define MEMCG_OOMLEAVE_RATIO 0.88
+#define BtoMB(x) ((x)>>20)
+#define KBtoMB(x) ((x)>>10)
+#define MBtoB(x) ((x)<<20)
+#define MBtoKB(x) ((x)<<10)
#define MEMNOTIFY_NORMAL 0x0000
-#define MEMNOTIFY_RECLAIM 0xecae
#define MEMNOTIFY_LOW 0xfaac
#define MEMNOTIFY_CRITICAL 0xdead
-/* define threshold limit */
-#define MAX_OOM_THRES 0x04600000 /* 70M */
-#define MIN_OOM_THRES 0x03000000 /* 48M */
-#define MAX_WARN_THRES 0x07800000 /* 120M */
-#define MAX_LEAVE_THRES 0x0B400000 /* 180M */
-#define MIN_OOM_WARN_GAP 0x01400000 /* 30M */
-
-#define MEM_THRESHOLD_RECLAIM 300
#define MEM_THRESHOLD_LV1 180
#define MEM_THRESHOLD_LV2 160
#define MEM_LEAVE_THRESHOLD 200
@@ -142,38 +87,15 @@ static int cur_mem_state = MEMNOTIFY_NORMAL;
static Ecore_Timer *oom_check_timer;
#define OOM_TIMER_INTERVAL 3
#define OOM_MULTIKILL_WAIT (1000*1000)
-#define OOM_CHECK_PROC_WAIT (2000*1000)
-
-unsigned int oom_delete_sm_time;
/* low memory action function */
static int memory_low_act(void *ad);
static int memory_oom_act(void *ad);
static int memory_normal_act(void *ad);
-static int memory_reclaim_act(void *ad);
-
-
-/* low memory action function for cgroup */
-static int memory_cgroup_oom_act(int memcg_index);
static int lowmem_fd_start();
static int lowmem_fd_stop(int fd);
-struct memcg_class {
- unsigned int event_fd;
- unsigned int min_limit;
- float limit_ratio;
- unsigned int oomlevel;
- unsigned int oomalert;
- unsigned int oomleave;
- char *cgroup_name;
- unsigned int total_limit;
- unsigned int thres_lv1;
- unsigned int thres_lv2;
- unsigned int thres_lv3;
- unsigned int thres_leave;
-};
-
struct lowmem_process_entry {
unsigned cur_mem_state;
unsigned new_mem_state;
@@ -181,82 +103,45 @@ struct lowmem_process_entry {
};
static struct lowmem_process_entry lpe[] = {
- {MEMNOTIFY_NORMAL, MEMNOTIFY_RECLAIM, memory_reclaim_act},
- {MEMNOTIFY_NORMAL, MEMNOTIFY_LOW, memory_low_act},
- {MEMNOTIFY_NORMAL, MEMNOTIFY_CRITICAL, memory_oom_act},
- {MEMNOTIFY_RECLAIM, MEMNOTIFY_LOW, memory_low_act},
- {MEMNOTIFY_RECLAIM, MEMNOTIFY_CRITICAL, memory_oom_act},
- {MEMNOTIFY_LOW, MEMNOTIFY_CRITICAL, memory_oom_act},
+ {MEMNOTIFY_NORMAL, MEMNOTIFY_LOW, memory_low_act},
+ {MEMNOTIFY_NORMAL, MEMNOTIFY_CRITICAL, memory_oom_act},
+ {MEMNOTIFY_LOW, MEMNOTIFY_CRITICAL, memory_oom_act},
+ {MEMNOTIFY_LOW, MEMNOTIFY_NORMAL, memory_normal_act},
{MEMNOTIFY_CRITICAL, MEMNOTIFY_CRITICAL, memory_oom_act},
- {MEMNOTIFY_LOW, MEMNOTIFY_RECLAIM, memory_reclaim_act},
- {MEMNOTIFY_LOW, MEMNOTIFY_NORMAL, memory_normal_act},
{MEMNOTIFY_CRITICAL, MEMNOTIFY_NORMAL, memory_normal_act},
- {MEMNOTIFY_CRITICAL, MEMNOTIFY_RECLAIM, memory_reclaim_act},
- {MEMNOTIFY_RECLAIM, MEMNOTIFY_NORMAL, memory_normal_act},
-};
-
-static struct memcg_class memcg_class[MEMCG_GROUP_MAX] = {
- {0, MEMCG_FOREGROUND_MIN_LIMIT, MEMCG_FOREGROUND_LIMIT_RATIO, 0, 0, 0, "foreground",
- 0, 0, 0, 0, 0},
- {0, MEMCG_BACKGROUND_MIN_LIMIT, MEMCG_BACKGROUND_LIMIT_RATIO, 0, 0, 0, "background",
- 0, 0, 0, 0, 0},
};
static const struct module_ops memory_modules_ops;
static const struct module_ops *lowmem_ops;
-unsigned int get_available(void)
+void lowmem_dynamic_process_killer(int type)
{
- char buf[PATH_MAX];
- FILE *fp;
- char *idx;
- unsigned int free = 0, cached = 0;
- unsigned int available = 0;
-
- fp = fopen(MEMINFO_PATH, "r");
- if (!fp) {
- _E("%s open failed, %d", buf, fp);
- return available;
- }
-
- while (fgets(buf, PATH_MAX, fp) != NULL) {
- if ((idx = strstr(buf, "MemFree:"))) {
- idx += strlen("MemFree:");
- while (*idx < '0' || *idx > '9')
- idx++;
- free = atoi(idx);
- } else if ((idx = strstr(buf, "MemAvailable:"))) {
- idx += strlen("MemAvailable:");
- while (*idx < '0' || *idx > '9')
- idx++;
- available = atoi(idx);
- break;
- } else if((idx = strstr(buf, "Cached:"))) {
- idx += strlen("Cached:");
- while (*idx < '0' || *idx > '9')
- idx++;
- cached = atoi(idx);
- break;
- }
- }
-
- if (available == 0)
- available = free + cached;
- available >>= 10;
- fclose(fp);
-
- return available;
+ /* This function is not supported */
}
-void lowmem_dynamic_process_killer(int type)
+static int convert_memory_state_type(int state)
{
- /* This function is not supported */
+ switch (state) {
+ case LOWMEM_NORMAL:
+ return MEMNOTIFY_NORMAL;
+ case LOWMEM_LOW:
+ return MEMNOTIFY_LOW;
+ case LOWMEM_MEDIUM:
+ return MEMNOTIFY_CRITICAL;
+ default:
+ _E("Invalid state (%d)", state);
+ return -EINVAL;
+ }
}
void change_memory_state(int state, int force)
{
int mem_state;
+ state = convert_memory_state_type(state);
+ if (state < 0)
+ return;
+
if (force) {
mem_state = state;
} else {
@@ -268,9 +153,6 @@ void change_memory_state(int state, int force)
case MEMNOTIFY_NORMAL:
memory_normal_act(NULL);
break;
- case MEMNOTIFY_RECLAIM:
- memory_reclaim_act(NULL);
- break;
case MEMNOTIFY_LOW:
memory_low_act(NULL);
break;
@@ -278,144 +160,9 @@ void change_memory_state(int state, int force)
memory_oom_act(NULL);
break;
default:
- assert(0);
- }
-}
-
-static unsigned int _get_total_memory(void)
-{
- char buf[PATH_MAX];
- FILE *fp;
- char *idx;
- unsigned int total = 0;
-
- fp = fopen(MEMINFO_PATH, "r");
- while (fgets(buf, PATH_MAX, fp) != NULL) {
- if ((idx = strstr(buf, "MemTotal:"))) {
- idx += strlen("MemTotal:");
- while (*idx < '0' || *idx > '9')
- idx++;
- total = atoi(idx);
- total *= 1024;
- break;
- }
- }
- fclose(fp);
- return total;
-}
-
-static void _calc_threshold(int type, int limit)
-{
- unsigned int val, check;
-
- /* calculate theshold lv3 */
- val = (unsigned int)(memcg_class[type].total_limit*
- (float)MEMCG_THRES_OOM_RATIO);
-
- /* check MIN & MAX value about threshold lv3*/
- if (limit - val > MAX_OOM_THRES)
- val = (unsigned int)(limit - MAX_OOM_THRES);
- else if (limit - val < MIN_OOM_THRES)
- val = (unsigned int)(limit - MIN_OOM_THRES);
-
- /* set threshold lv3 */
- memcg_class[type].thres_lv3 = val;
-
- /* calculate threshold lv2 */
- val = (unsigned int)(memcg_class[type].total_limit*
- (float)MEMCG_THRES_WARNING_RATIO);
-
- check = memcg_class[type].thres_lv3;
-
- /* check MIN & MAX value about threshold lv2*/
- if (check - val < MIN_OOM_WARN_GAP)
- val = (unsigned int)(check - MIN_OOM_WARN_GAP);
- else if (limit - val > MAX_WARN_THRES)
- val = (unsigned int)(limit - MAX_WARN_THRES);
-
- /* set threshold lv2 */
- memcg_class[type].thres_lv2 = val;
-
- /* calculate threshold lv1 */
- val = (unsigned int)(memcg_class[type].total_limit*
- (float)MEMCG_TRHES_SOFTSWAP_RATIO);
-
- /* check MIN value about threshold lv1*/
- check = memcg_class[type].thres_lv2;
-
- if (check - val < MIN_OOM_WARN_GAP)
- val = (unsigned int)(check - MIN_OOM_WARN_GAP);
-
- memcg_class[type].thres_lv1 = val;
-
- /* set leave threshold */
- val = (unsigned int)(memcg_class[type].total_limit*
- (float)MEMCG_OOMLEAVE_RATIO);
-
- check = memcg_class[type].thres_lv1;
-
- /* check MIN & MAX value about leave threshold */
- if (check - val < MIN_OOM_WARN_GAP)
- val = (unsigned int)(check - MIN_OOM_WARN_GAP);
- else if (limit - val > MAX_LEAVE_THRES)
- val = (unsigned int)(limit - MAX_WARN_THRES);
-
- memcg_class[type].oomleave = val;
-}
-
-static unsigned int get_mem_usage(int idx)
-{
- FILE *f;
- char buf[LOWMEM_PATH_MAX] = {0,};
- unsigned int usage;
-
- sprintf(buf, "%s/%s/memory.usage_in_bytes",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
-
- f = fopen(buf, "r");
- if (!f) {
- _E("%s open failed, %d", buf, f);
- return RESOURCED_ERROR_FAIL;
- }
- if (fgets(buf, 32, f) == NULL) {
- _E("fgets failed\n");
- fclose(f);
- return RESOURCED_ERROR_FAIL;
- }
- usage = atoi(buf);
- fclose(f);
-
- return usage;
-}
-
-static int get_current_oom(int idx)
-{
- FILE *f;
- char buf[LOWMEM_PATH_MAX] = {0,};
- char *oom;
- unsigned int level;
-
- sprintf(buf, "%s/%s/memory.oom_usr_control",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
-
- f = fopen(buf, "r");
- if (!f) {
- _E("%s open failed, %d", buf, f);
- return RESOURCED_ERROR_FAIL;
- }
- if (fgets(buf, 32, f) == NULL) {
- _E("fgets failed\n");
- fclose(f);
- return RESOURCED_ERROR_FAIL;
+ _E("Invalid mem state (%d)", mem_state);
+ return;
}
- oom = strstr(buf, "oom_usr_control");
- oom += strlen("oom_usr_control");
- while (*oom < '0' || *oom > '9')
- oom++;
- level = atoi(oom);
- fclose(f);
- _D("get_current_oom : %d", level);
- return level;
}
static int remove_shm(void)
@@ -445,14 +192,7 @@ static int remove_shm(void)
static void print_mem_state(void)
{
- unsigned int usage, i;
-
- for (i = 0; i < MEMCG_GROUP_MAX; i++) {
- usage = get_mem_usage(i);
- _I("[MEM STATE] memcg : %s, usage %d oom level : %d",
- memcg_class[i].cgroup_name, usage,
- memcg_class[i].oomlevel);
- }
+ _I("[MEM STATE] usage (%d)", get_mem_usage());
}
static void make_memps_log(char *file, pid_t pid, char *victim_name)
@@ -492,26 +232,6 @@ static void make_memps_log(char *file, pid_t pid, char *victim_name)
}
}
-static int lowmem_check_current_state(int memcg_index,
- int total_size, int oom_usage)
-{
- unsigned int usage, oomleave, check = 0;
-
- oomleave = memcg_class[memcg_index].oomleave;
- usage = get_mem_usage(memcg_index);
- if (usage < oomleave) {
- _D("%s : usage : %d, oomleave : %d",
- __func__, usage, oomleave);
- check++;
- }
- if (oom_usage - total_size < oomleave) {
- _D("%s : oom_usage : %d, total size : %d, oomleave : %d",
- __func__, oom_usage, total_size, oomleave);
- check++;
- }
- return check;
-}
-
static int lowmem_get_victim_pid(int *pid_arry, unsigned int* pid_size)
{
int count, num_pid = 0;
@@ -561,46 +281,9 @@ out:
}
-static int lowmem_set_cgroup_leave_threshold(unsigned int value)
-{
- FILE *f;
- f = fopen(SET_CGROUP_LEAVE_THRESHOLD, "w");
-
- if (!f) {
- _E("Fail to file open");
- return RESOURCED_ERROR_FAIL;
- }
- fprintf(f, "%d", value);
- fclose(f);
- return 0;
-}
-
static int lowmem_set_threshold(void)
{
FILE *f;
- unsigned int val, total;
-
- f = fopen(SET_THRESHOLD_RECLAIM, "w");
-
- if (!f) {
- _E("Fail to file open : current kernel can't support swap cgroup");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* set threshold reclaim */
- total = _get_total_memory();
-
- /*
- * check total memory because total memory is over 1GiB,
- * we want to start reclaim under 300 MiB remained memory.
- * But, we check condition 700MiB because reserved memory.
- */
- if (total > MBtoB(700))
- val = MEM_THRESHOLD_RECLAIM;
- else
- val = MEM_THRESHOLD_RECLAIM >> 1;
- fprintf(f, "%d", val);
- fclose(f);
/* set threshold level1 */
f = fopen(SET_THRESHOLD_LV1, "w");
@@ -622,15 +305,6 @@ static int lowmem_set_threshold(void)
fprintf(f, "%d", MEM_THRESHOLD_LV2);
fclose(f);
- /* set leave threshold */
- f = fopen(SET_LEAVE_THRESHOLD, "w");
-
- if (!f) {
- _E("Fail to file open");
- return RESOURCED_ERROR_FAIL;
- }
- fprintf(f, "%d", MEM_LEAVE_THRESHOLD);
- fclose(f);
return 0;
}
@@ -713,85 +387,11 @@ void *_lowmem_oom_killer_cb(void *data)
return NULL;
}
-int lowmem_oom_killer_cb(int memcg_idx, int flags)
-{
- int memcg_index = memcg_idx;
- _lowmem_oom_killer_cb((void *)&memcg_index);
- return 0;
-}
-
-static void lowmem_cgroup_oom_killer(int memcg_index)
-{
- int pid, ret, oom_score_adj, count, i;
- char appname[PATH_MAX];
- int pid_array[32];
- unsigned int pid_size[32];
- unsigned int total_size = 0, oom_usage = 0;
-
- oom_usage = get_mem_usage(memcg_index);
- /* get multiple victims from kernel */
- count = lowmem_get_victim_pid((int *)pid_array,
- (unsigned int *)pid_size);
-
- if (count < 0) {
- _E("get victim was failed");
- return;
- }
-
- for (i = 0; i < count; i++) {
- pid = pid_array[i];
-
- if (pid <= 0)
- continue;
- _D("oom total memory size : %d", total_size);
- ret = proc_get_cmdline(pid, appname);
- if (ret != 0) {
- _E("invalid pid(%d) was selected", pid);
- continue;
- }
- if (!strcmp("memps", appname)) {
- _E("memps(%d) was selected, skip it", pid);
- continue;
- }
- if (!strcmp("crash-worker", appname)) {
- _E("crash-worker(%d) was selected, skip it", pid);
- continue;
- }
- if (proc_get_oom_score_adj(pid, &oom_score_adj) < 0) {
- _D("pid(%d) was already terminated", pid);
- continue;
- }
-
- /* check current memory status */
- if (lowmem_check_current_state(memcg_index, total_size,
- oom_usage) > 0)
- return;
-
- /* make memps log for killing application firstly */
- if (i==0)
- make_memps_log(MEMPS_LOG_FILE, pid, appname);
-
- proc_remove_process_list(pid);
- kill(pid, SIGTERM);
-
- total_size += pid_size[i];
- _I("we killed, lowmem lv2 = %d (%s) oom = %d\n",
- pid, appname, oom_score_adj);
-
- if (oom_score_adj > OOMADJ_FOREGRD_UNLOCKED)
- continue;
-
- if (i != 0)
- make_memps_log(MEMPS_LOG_FILE, pid, appname);
- }
-}
-
static char *convert_to_str(unsigned int mem_state)
{
char *tmp = NULL;
switch (mem_state) {
case MEMNOTIFY_NORMAL:
- case MEMNOTIFY_RECLAIM:
tmp = "mem normal";
break;
case MEMNOTIFY_LOW:
@@ -812,49 +412,6 @@ static void print_lowmem_state(unsigned int mem_state)
convert_to_str(mem_state));
}
-static void lowmem_swap_memory(void)
-{
- pid_t pid;
- int swap_type;
-
- if (cur_mem_state == MEMNOTIFY_NORMAL)
- return;
-
- swap_type = swap_status(SWAP_GET_TYPE, NULL);
-
- if (swap_type == SWAP_ON) {
- while (1)
- {
- pid = (pid_t)swap_status(SWAP_GET_CANDIDATE_PID, NULL);
- if (!pid)
- break;
- _I("swap cgroup entered : pid : %d", (int)pid);
- resourced_notify(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, (void*)&pid);
- }
- if (swap_status(SWAP_GET_STATUS, NULL) == SWAP_OFF)
- resourced_notify(RESOURCED_NOTIFIER_SWAP_RESTART, NULL);
- resourced_notify(RESOURCED_NOTIFIER_SWAP_START, NULL);
- }
-}
-
-static int memory_reclaim_act(void *data)
-{
- int ret, status;
- _I("[LOW MEM STATE] memory reclaim state");
- ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
- if (ret != 0) {
- _E("vconf get failed(VCONFKEY_SYSMAN_LOW_MEMORY)\n");
- return RESOURCED_ERROR_FAIL;
- }
- if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL)
- vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
- VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
- else
- lowmem_swap_memory();
-
- return 0;
-}
-
static int memory_low_act(void *data)
{
_I("[LOW MEM STATE] memory low state");
@@ -863,6 +420,7 @@ static int memory_low_act(void *data)
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING);
+ memory_level_send_system_event(MEMORY_LEVEL_LOW);
return 0;
}
@@ -885,19 +443,7 @@ static int memory_oom_act(void *ad)
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
- return 1;
-}
-
-static int memory_cgroup_oom_act(int memcg_index)
-{
- _I("[LOW MEM STATE] memory oom state");
-
- print_mem_state();
-
- lowmem_cgroup_oom_killer(memcg_index);
-
- vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
- VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
+ memory_level_send_system_event(MEMORY_LEVEL_CRITICAL);
return 1;
}
@@ -906,6 +452,7 @@ static int memory_normal_act(void *data)
_I("[LOW MEM STATE] memory normal state");
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+ memory_level_send_system_event(MEMORY_LEVEL_NORMAL);
return 0;
}
@@ -931,302 +478,29 @@ static int lowmem_process(unsigned int mem_state, void *ad)
return 0;
}
-static unsigned int lowmem_eventfd_read(int fd)
-{
- unsigned int ret;
- uint64_t dummy_state;
- ret = read(fd, &dummy_state, sizeof(dummy_state));
- return ret;
-}
-
-static Eina_Bool lowmem_cb(void *data, Ecore_Fd_Handler *fd_handler)
-{
- int fd, i, currentoom;
- struct ss_main_data *ad = (struct ss_main_data *)data;
-
- if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
- _E("ecore_main_fd_handler_active_get error , return\n");
- return ECORE_CALLBACK_CANCEL;
- }
-
- fd = ecore_main_fd_handler_fd_get(fd_handler);
- if (fd < 0) {
- _E("ecore_main_fd_handler_fd_get error , return\n");
- return ECORE_CALLBACK_CANCEL;
- }
- lowmem_eventfd_read(fd);
-
- for (i = 0; i < MEMCG_GROUP_MAX; i++) {
- currentoom = get_current_oom(i);
- if (currentoom == MEMGC_OOM_NORMAL) {
- if (memcg_class[i].oomalert)
- memory_normal_act(ad);
- }
- if (currentoom > memcg_class[i].oomlevel) {
- switch (currentoom) {
- case MEMGC_OOM_WARNING:
- memory_low_act(ad);
- break;
- case MEMGC_OOM_HIGH:
- memcg_class[i].oomalert = 1;
- memory_cgroup_oom_act(i);
- break;
- case MEMGC_OOM_CRITICAL:
- memcg_class[i].oomalert = 1;
- break;
- default:
- break;
- }
- }
- memcg_class[i].oomlevel = currentoom;
- }
-
- return ECORE_CALLBACK_RENEW;
-}
-
-/*
-From memory.txt kernel document -
-To register a notifier, application need:
-- create an eventfd using eventfd(2)
-- open memory.oom_control file
-- write string like "<event_fd> <fd of memory.oom_control>"
-to cgroup.event_control
-*/
-
-static int setup_eventfd(void)
+static unsigned int lowmem_read(int fd)
{
- unsigned int thres, i;
- int mcgfd, cgfd, evfd, res, sz, ret = -1;
- char buf[LOWMEM_PATH_MAX] = {0,};
-
- /* create an eventfd using eventfd(2)
- use same event fd for using ecore event loop */
- evfd = eventfd(0, 0);
- ret = fcntl(evfd, F_SETFL, O_NONBLOCK);
- if (ret < 0)
+ unsigned int mem_state;
+ if (read(fd, &mem_state, sizeof(mem_state)) < 0) {
+ _E("error lowmem state");
return RESOURCED_ERROR_FAIL;
-
- for (i = 0; i < MEMCG_GROUP_MAX; i++) {
- /* open cgroup.event_control */
- sprintf(buf, "%s/%s/cgroup.event_control",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- cgfd = open(buf, O_WRONLY);
- if (cgfd < 0) {
- _E("open event_control failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* register event in usage_in_byte */
- sprintf(buf, "%s/%s/memory.usage_in_bytes",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- mcgfd = open(buf, O_RDONLY);
- if (mcgfd < 0) {
- _E("open memory control failed");
- close(cgfd);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* threshold lv 1 : wakeup softswapd */
- /* write event fd about threshold lv1 */
- thres = memcg_class[i].thres_lv1;
- sz = sprintf(buf, "%d %d %d", evfd, mcgfd, thres);
- sz += 1;
- res = write(cgfd, buf, sz);
- if (res != sz) {
- _E("write cgfd failed : %d", res);
- close(cgfd);
- close(mcgfd);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* calculate threshold lv_2 */
- /* threshold lv 2 : lowmem warning */
- thres = memcg_class[i].thres_lv2;
-
- /* write event fd about threshold lv1 */
- sz = sprintf(buf, "%d %d %d", evfd, mcgfd, thres);
- sz += 1;
- res = write(cgfd, buf, sz);
- if (res != sz) {
- _E("write cgfd failed : %d", res);
- close(cgfd);
- close(mcgfd);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* calculate threshold lv_3 */
- /* threshold lv 3 : victim kill */
- thres = memcg_class[i].thres_lv3;
-
- /* write event fd about threshold lv2 */
- sz = sprintf(buf, "%d %d %d", evfd, mcgfd, thres);
- sz += 1;
- res = write(cgfd, buf, sz);
- if (res != sz) {
- _E("write cgfd failed : %d", res);
- close(cgfd);
- close(mcgfd);
- return RESOURCED_ERROR_FAIL;
- }
- close(mcgfd);
-
- /* register event in oom_control */
- sprintf(buf, "%s/%s/memory.oom_control",
- MEMCG_PATH, memcg_class[i].cgroup_name);
-
- mcgfd = open(buf, O_RDONLY);
- if (mcgfd < 0) {
- _E("open memory control failed");
- close(cgfd);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* write event fd about oom control with zero threshold*/
- thres = 0;
- sz = sprintf(buf, "%d %d %d", evfd, mcgfd, thres);
- sz += 1;
- res = write(cgfd, buf, sz);
- if (res != sz) {
- _E("write cgfd failed : %d", res);
- close(cgfd);
- close(mcgfd);
- return RESOURCED_ERROR_FAIL;
- }
- close(cgfd);
- close(mcgfd);
}
- return evfd;
-}
-
-void set_threshold(int level, int thres)
-{
- return;
-}
-
-void set_leave_threshold(int thres)
-{
- return;
-}
-
-static int init_memcg(void)
-{
- unsigned int total, i, limit, size;
- char buf[LOWMEM_PATH_MAX] = {0,};
- FILE *f;
- total = _get_total_memory();
- _D("Total : %d", total);
-
- for (i = 0; i < MEMCG_GROUP_MAX; i++) {
- /* write limit_in_bytes */
- sprintf(buf, "%s/%s/memory.limit_in_bytes",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- _D("buf : %s", buf);
- f = fopen(buf, "w");
- if (!f) {
- _E("%s open failed", buf);
- return RESOURCED_ERROR_FAIL;
- }
-
- limit = (unsigned int)(memcg_class[i].limit_ratio*(float)total);
-
- if (limit > memcg_class[i].min_limit)
- limit = memcg_class[i].min_limit;
-
- size = sprintf(buf, "%u", limit);
- if (fwrite(buf, size, 1, f) != 1)
- _E("fwrite memory.limit_in_bytes : %d\n", limit);
- fclose(f);
-
- /* save memory limitation for calculating threshold */
- memcg_class[i].total_limit = limit;
-
- _calc_threshold(i, limit);
-
- /* set leave threshold value to kernel */
- lowmem_set_cgroup_leave_threshold(memcg_class[i].oomleave);
-
- /* enable cgroup move */
- sprintf(buf, "%s/%s/memory.move_charge_at_immigrate",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- _D("buf : %s", buf);
- f = fopen(buf, "w");
- if (!f) {
- _E("%s open failed", buf);
- return RESOURCED_ERROR_FAIL;
- }
- size = sprintf(buf, "3");
- if (fwrite(buf, size, 1, f) != 1)
- _E("fwrite memory.move_charge_at_immigrate\n");
- fclose(f);
-
- }
- return 0;
+ return mem_state;
}
-static void lowmem_move_memcgroup(int pid, int oom_score_adj)
+int lowmem_memory_oom_killer(int flags)
{
- char buf[LOWMEM_PATH_MAX] = {0,};
- FILE *f;
- int size, background = 0;
- unsigned long swap_args[1] = {0,};
-
- if (oom_score_adj > OOMADJ_BACKGRD_LOCKED) {
- sprintf(buf, "%s/background/cgroup.procs", MEMCG_PATH);
- background = 1;
- }
- else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED &&
- oom_score_adj < OOMADJ_BACKGRD_LOCKED)
- sprintf(buf, "%s/foreground/cgroup.procs", MEMCG_PATH);
- else
- return;
-
- swap_args[0] = (unsigned long)pid;
- if (!swap_status(SWAP_CHECK_PID, swap_args) || !background) {
- _I("buf : %s, pid : %d, oom : %d", buf, pid, oom_score_adj);
- f = fopen(buf, "w");
- if (!f) {
- _E("%s open failed", buf);
- return;
- }
- size = sprintf(buf, "%d", pid);
- if (fwrite(buf, size, 1, f) != 1)
- _E("fwrite cgroup tasks : %d\n", pid);
- fclose(f);
- }
- if (background)
- lowmem_swap_memory();
+ return memory_oom_act(NULL);
}
-static void lowmem_cgroup_foregrd_manage(int currentpid)
+void lowmem_memcg_set_threshold(int idx, int level, int value)
{
- char buf[LOWMEM_PATH_MAX] = {0,};
- int pid, pgid;
- FILE *f;
- sprintf(buf, "%s/background/cgroup.procs", MEMCG_PATH);
- f = fopen(buf, "r");
- if (!f) {
- _E("%s open failed", buf);
- return;
- }
- while (fgets(buf, LOWMEM_PATH_MAX, f) != NULL) {
- pid = atoi(buf);
- if (currentpid == pid)
- continue;
- pgid = getpgid(pid);
- if (currentpid == pgid)
- lowmem_move_memcgroup(pid, OOMADJ_APP_LIMIT);
- }
- fclose(f);
+ /* This function is for vmpressure */
}
-static unsigned int lowmem_read(int fd)
+void lowmem_memcg_set_leave_threshold(int idx, int value)
{
- unsigned int mem_state;
- if (read(fd, &mem_state, sizeof(mem_state)) < 0) {
- _E("error lowmem state");
- return RESOURCED_ERROR_FAIL;
- }
- return mem_state;
+ /* This function is for vmpressure */
}
static Eina_Bool lowmem_efd_cb(void *data, Ecore_Fd_Handler *fd_handler)
@@ -1262,7 +536,7 @@ static Eina_Bool lowmem_efd_cb(void *data, Ecore_Fd_Handler *fd_handler)
static int lowmem_fd_start(void)
{
- lowmem_fd = open("/dev/lowmemnotify", O_RDONLY);
+ lowmem_fd = open(DEV_MEMNOTIFY, O_RDONLY);
if (lowmem_fd < 0) {
_E("lowmem_fd_start fd open failed");
return RESOURCED_ERROR_FAIL;
@@ -1284,13 +558,6 @@ int lowmem_init(void)
{
int ret = RESOURCED_ERROR_NONE;
- /* set default memcg value */
- ret = init_memcg();
- if (ret < 0) {
- _E("memory cgroup init failed");
- return RESOURCED_ERROR_FAIL;
- }
-
ret = lowmem_fd_start();
if (ret < 0) {
_E("lowmem_fd_start fail\n");
@@ -1304,18 +571,6 @@ int lowmem_init(void)
return RESOURCED_ERROR_FAIL;
}
- /* register threshold and event fd */
- lowmem_fd = setup_eventfd();
- if (lowmem_fd < 0) {
- _E("setup event fd is failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- ecore_main_fd_handler_add(lowmem_fd, ECORE_FD_READ,
- (Ecore_Fd_Cb)lowmem_cb, NULL, NULL, NULL);
-
- _I("lowmem_swaptype : %d", swap_status(SWAP_GET_TYPE, NULL));
-
lowmem_dbus_init();
return 0;
@@ -1336,22 +591,7 @@ static int lowmem_fd_stop(int fd)
static int resourced_memory_control(void *data)
{
- int ret = RESOURCED_ERROR_NONE;
- struct lowmem_data_type *l_data;
-
- l_data = (struct lowmem_data_type *)data;
- switch(l_data->control_type) {
- case LOWMEM_MOVE_CGROUP:
- if (l_data->args)
- lowmem_move_memcgroup((pid_t)l_data->args[0], l_data->args[1]);
- break;
- case LOWMEM_MANAGE_FOREGROUND:
- if (l_data->args)
- lowmem_cgroup_foregrd_manage((pid_t)l_data->args[0]);
- break;
-
- }
- return ret;
+ return RESOURCED_ERROR_NONE;
}
static int resourced_memory_init(void *data)
@@ -1368,14 +608,6 @@ static int resourced_memory_finalize(void *data)
int lowmem_control(enum lowmem_control_type type, unsigned long *args)
{
- struct lowmem_data_type l_data;
-
- if (lowmem_ops) {
- l_data.control_type = type;
- l_data.args = args;
- return lowmem_ops->control(&l_data);
- }
-
return RESOURCED_ERROR_NONE;
}
diff --git a/src/memory/lowmem-handler.h b/src/memory/lowmem-handler.h
index d938ddde..4981f5c8 100644
--- a/src/memory/lowmem-handler.h
+++ b/src/memory/lowmem-handler.h
@@ -27,28 +27,27 @@
#define __LOWMEM_HANDLER_H__
void lowmem_dbus_init(void);
-int lowmem_oom_killer_cb(int memcg_idx, int flags);
+int lowmem_memory_oom_killer(int flags);
void lowmem_dynamic_process_killer(int type);
unsigned int get_available(void);
void change_memory_state(int state, int force);
+void lowmem_memcg_set_threshold(int idx, int level, int value);
+void lowmem_memcg_set_leave_threshold(int idx, int value);
-void set_threshold(int level, int thres);
-void set_leave_threshold(int thres);
-
-#define NUM_FOREGROUND 3
enum {
MEMCG_MEMORY,
MEMCG_FOREGROUND,
- MEMCG_BACKGROUND = MEMCG_FOREGROUND + NUM_FOREGROUND,
- MEMCG_MAX_GROUPS,
+ MEMCG_BACKGROUND,
+ MEMCG_SWAP,
+ MEMCG_MAX,
};
enum {
- MEMNOTIFY_NORMAL,
- MEMNOTIFY_SWAP,
- MEMNOTIFY_LOW,
- MEMNOTIFY_MEDIUM,
- MEMNOTIFY_MAX_LEVELS,
+ LOWMEM_NORMAL,
+ LOWMEM_SWAP,
+ LOWMEM_LOW,
+ LOWMEM_MEDIUM,
+ LOWMEM_MAX_LEVEL,
};
enum oom_killer_cb_flags {
diff --git a/src/memory/memcontrol.c b/src/memory/memcontrol.c
new file mode 100644
index 00000000..adec82c7
--- /dev/null
+++ b/src/memory/memcontrol.c
@@ -0,0 +1,146 @@
+/*
+ * 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 memcontrol.c
+ *
+ * @desc structure and operation for memory cgroups
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "macro.h"
+#include "memcontrol.h"
+
+void memcg_info_set_limit(struct memcg_info_t *mi, float ratio,
+ unsigned int totalram)
+{
+ if (!mi)
+ return;
+
+ mi->limit = (float)totalram * ratio;
+ mi->limit_ratio = ratio;
+ mi->threshold[LOWMEM_LOW] = (unsigned int)(mi->limit * MEMCG_LOW_RATIO);
+ mi->threshold[LOWMEM_MEDIUM] = (unsigned int)(mi->limit * MEMCG_MEDIUM_RATIO);
+ mi->threshold_leave = (float)mi->limit * MEMCG_FOREGROUND_LEAVE_RATIO;
+ mi->oomleave = mi->limit - mi->threshold_leave;
+}
+
+static struct memcg_info_t *memcg_info_alloc_subcgroup(struct memcg_t *memcg)
+{
+ struct memcg_info_t *pmi, *mi;
+ int i;
+ if (!memcg)
+ return NULL;
+ mi = (struct memcg_info_t *)malloc(sizeof(struct memcg_info_t));
+ if (!mi)
+ return NULL;
+ mi->id = memcg->num_subcgroup;
+ pmi = memcg->info;
+ snprintf(mi->name, MAX_PATH_LENGTH, "%s%d/",
+ pmi->name, memcg->num_subcgroup++);
+ mi->limit_ratio = pmi->limit_ratio;
+ mi->limit = pmi->limit;
+ mi->oomleave = pmi->oomleave;
+ for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
+ mi->threshold[i] = pmi->threshold[i];
+ mi->threshold_leave = pmi->threshold_leave;
+ strncpy(mi->event_level, pmi->event_level,
+ MAX_NAME_LENGTH);
+ mi->evfd = pmi->evfd;
+ return mi;
+}
+
+static int memcg_add_cgroup(struct memcg_t *memcg)
+{
+ struct memcg_info_t *mi = NULL;
+ if (!memcg)
+ return RESOURCED_ERROR_FAIL;
+ mi = memcg_info_alloc_subcgroup(memcg);
+ if (!mi)
+ return RESOURCED_ERROR_FAIL;
+ memcg->cgroups = g_slist_prepend(memcg->cgroups, mi);
+ return RESOURCED_ERROR_NONE;
+}
+
+int memcg_add_cgroups(struct memcg_t *memcg, int num)
+{
+ int i, ret = RESOURCED_ERROR_NONE;
+ for (i = 0; i < num; i++) {
+ ret = memcg_add_cgroup(memcg);
+ if (ret == RESOURCED_ERROR_FAIL)
+ return ret;
+ }
+ return ret;
+}
+
+static void memcg_info_show(struct memcg_info_t *mi)
+{
+ int i;
+ _D("======================================");
+ _D("memcg_info->name = %s", mi->name);
+ _D("memcg_info->limit_ratio = %.f", mi->limit_ratio);
+ _D("memcg_info->limit = %u", mi->limit);
+ _D("memcg_info->oomleave = %u", mi->oomleave);
+ for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
+ _D("memcg_info->threshold = %u", mi->threshold[i]);
+ _D("memcg_info->threshold_leave = %u", mi->threshold_leave);
+ _D("memcg_info->event_level = %s", mi->event_level);
+ _D("memcg_info->evfd = %d", mi->evfd);
+}
+
+void memcg_show(struct memcg_t *memcg)
+{
+ GSList *iter = NULL;
+ memcg_info_show(memcg->info);
+ gslist_for_each_item(iter, memcg->cgroups) {
+ struct memcg_info_t *mi =
+ (struct memcg_info_t *)(iter->data);
+ memcg_info_show(mi);
+ }
+}
+
+void memcg_info_init(struct memcg_info_t *mi, const char *name)
+{
+ int i;
+ mi->id = 0;
+ mi->limit_ratio = 0;
+ mi->limit = 0;
+ mi->oomleave = 0;
+ for (i = 0; i < LOWMEM_MAX_LEVEL; i++)
+ mi->threshold[i] = 0;
+ mi->threshold_leave = 0;
+ mi->evfd = -1;
+ strncpy(mi->event_level, MEMCG_DEFAULT_EVENT_LEVEL,
+ MAX_NAME_LENGTH);
+ strncpy(mi->name, name, MAX_PATH_LENGTH);
+}
+
+void memcg_init(struct memcg_t *memcg)
+{
+ memcg->num_subcgroup = MEMCG_DEFAULT_NUM_SUBCGROUP;
+ memcg->use_hierarchy = MEMCG_DEFAULT_USE_HIERARCHY;
+ memcg->info = NULL;
+ memcg->cgroups = NULL;
+}
diff --git a/src/memory/memcontrol.h b/src/memory/memcontrol.h
new file mode 100644
index 00000000..6bab45f2
--- /dev/null
+++ b/src/memory/memcontrol.h
@@ -0,0 +1,77 @@
+/*
+ * 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 memcontrol.h
+ * @desc header file for handling memory cgroups
+ **/
+
+#ifndef __MEMCONTROL_H__
+#define __MEMCONTROL_H__
+
+#include <glib.h>
+#include "lowmem-handler.h"
+#include "const.h"
+
+/* number of memory cgroups */
+#define MEMCG_DEFAULT_NUM_SUBCGROUP 0
+#define MEMCG_DEFAULT_EVENT_LEVEL "medium"
+#define MEMCG_DEFAULT_USE_HIERARCHY 0
+
+#define MEMCG_LOW_RATIO 0.8
+#define MEMCG_MEDIUM_RATIO 0.96
+#define MEMCG_FOREGROUND_LEAVE_RATIO 0.25
+
+struct memcg_info_t {
+ /* name of memory cgroup */
+ char name[MAX_PATH_LENGTH];
+ /* id for sub cgroup. 0 if no hierarchy, 0 ~ MAX if use hierarchy */
+ int id;
+ /* limit ratio, if don't want to set limit, use NO_LIMIT*/
+ float limit_ratio;
+ unsigned int limit;
+ /* leave memory usage */
+ unsigned int oomleave;
+ /* thresholds, normal, swap, low, medium, and leave */
+ unsigned int threshold[LOWMEM_MAX_LEVEL];
+ unsigned int threshold_leave;
+ /* vmpressure event string. If don't want to register event, use null */
+ char event_level[MAX_NAME_LENGTH];
+ int evfd;
+};
+
+struct memcg_t {
+ /* number of sub cgroups */
+ int num_subcgroup;
+ /* parent cgroup */
+ struct memcg_info_t *info;
+ /* set when using multiple sub cgroups */
+ int use_hierarchy;
+ /* list of child cgroups when using multi groups */
+ GSList *cgroups;
+};
+
+void memcg_info_set_limit(struct memcg_info_t *memcg_info, float ratio,
+ unsigned int totalram);
+void memcg_info_init(struct memcg_info_t *memcg_info, const char *name);
+void memcg_init(struct memcg_t *memcg);
+void memcg_show(struct memcg_t *memcg);
+int memcg_add_cgroups(struct memcg_t *memcg, int num);
+
+#endif /*__MEMCONTROL_H__*/
diff --git a/src/memory/memory_eng.conf b/src/memory/memory_eng.conf
index 81751d2f..c6a47582 100644
--- a/src/memory/memory_eng.conf
+++ b/src/memory/memory_eng.conf
@@ -53,14 +53,51 @@ ThresholdSwap=100 # MB
ThresholdLow=60 # MB
# Threshold to start low memory killer
-ThresholdMedium=40 # MB
+ThresholdMedium=50 # MB
# Threshold to stop low memory killer
ThresholdLeave=70 # MB
+# Threshold for dynamic memory killer
+DynamicThreshold=80 # MB
+
+# Leave Threshold for dynamic memory killer
+DynamicLeave=100 # MB
+
+# Foreground limit ratio
+ForegroundRatio=0.6
+
+# Number of max victims
+NumMaxVictims=5
+
+[Memory768]
+# Threshold to start swap
+ThresholdSwap=300 # MB
+
+# Threshold to start reclaim
+ThresholdLow=200 # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=100 # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=150 # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=150 # MB
+
+# Leave Threshold for dynamic memory killer
+DynamicLeave=230 # MB
+
# Foreground limit ratio
ForegroundRatio=0.6
+# Foreground use hierarchy
+# ForegroundUseHierarchy=1
+
+# Foreground # of cgroups
+# ForegroundNumCgroups=3
+
# Number of max victims
NumMaxVictims=5
diff --git a/src/memory/memory_user.conf b/src/memory/memory_user.conf
index f821ba23..8d5e0389 100644
--- a/src/memory/memory_user.conf
+++ b/src/memory/memory_user.conf
@@ -50,17 +50,48 @@ ThresholdSwap=100 # MB
ThresholdLow=60 # MB
# Threshold to start low memory killer
-ThresholdMedium=40 # MB
+ThresholdMedium=50 # MB
# Threshold to stop low memory killer
ThresholdLeave=70 # MB
+# Threshold for dynamic memory killer
+DynamicThreshold=80 # MB
+
+# Leave Threshold for dynamic memory killer
+DynamicLeave=100 # MB
+
# Foreground limit ratio
ForegroundRatio=1
# Number of max victims
NumMaxVictims=5
+[Memory768]
+# Threshold to start swap
+ThresholdSwap=300 # MB
+
+# Threshold to start reclaim
+ThresholdLow=200 # MB
+
+# Threshold to start low memory killer
+ThresholdMedium=100 # MB
+
+# Threshold to stop low memory killer
+ThresholdLeave=150 # MB
+
+# Threshold for dynamic memory killer
+DynamicThreshold=150 # MB
+
+# Leave Threshold for dynamic memory killer
+DynamicLeave=230 # MB
+
+# Foreground limit ratio
+ForegroundRatio=0.6
+
+# Number of max victims
+NumMaxVictims=5
+
[Memory1024]
# Threshold to start swap
ThresholdSwap=300 # MB
diff --git a/src/memory/vmpressure-lowmem-handler.c b/src/memory/vmpressure-lowmem-handler.c
index 0c0db5cb..27da2171 100644
--- a/src/memory/vmpressure-lowmem-handler.c
+++ b/src/memory/vmpressure-lowmem-handler.c
@@ -1,7 +1,7 @@
/*
* resourced
*
- * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2012 - 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.
@@ -17,11 +17,11 @@
*/
/*
- * @file lowmem_handler.c
+ * @file vmpressure-lowmem-handler.c
*
* @desc lowmem handler using memcgroup
*
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
*
*/
@@ -57,9 +57,15 @@
#include "config-parser.h"
#include "module.h"
#include "logging-common.h"
+#include "swap-common.h"
+#include "cgroup.h"
+#include "memcontrol.h"
+#include "helper.h"
+
+#define LOWMEM_DEFAULT_CGROUP "/sys/fs/cgroup/memory"
+#define LOWMEM_NO_LIMIT 0
+#define LOWMEM_THRES_INIT 0
-#define MEMINFO_PATH "/proc/meminfo"
-#define MEMCG_PATH "/sys/fs/cgroup"
#define MEMPS_LOG_PATH "/var/log/"
#define MEMPS_LOG_FILE MEMPS_LOG_PATH"memps"
#define MEMPS_EXEC_PATH "usr/bin/memps"
@@ -74,7 +80,6 @@
#define BtoKB(x) ((x) >> 10)
#define BtoPAGE(x) ((x) >> 12)
-#define NO_LIMIT -1
/* for memory cgroup, set no limit */
#define MEMCG_MEMORY_LIMIT_RATIO NO_LIMIT
#define MEMCG_FOREGROUND_LIMIT_RATIO 1
@@ -82,13 +87,9 @@
#define MEMCG_BACKGROUND_LIMIT_RATIO NO_LIMIT
#define MEMCG_FOREGROUND_MIN_LIMIT UINT_MAX
#define MEMCG_BACKGROUND_MIN_LIMIT UINT_MAX
-#define MEMCG_LOW_RATIO 0.8
-#define MEMCG_MEDIUM_RATIO 0.96
#define MEMCG_FOREGROUND_THRES_LEAVE 100 /* MB */
-#define MEMCG_FOREGROUND_LEAVE_RATIO 0.25
#define BUF_MAX 1024
-#define LOWMEM_PATH_MAX 100
#define MAX_MEMORY_CGROUP_VICTIMS 10
#define MAX_CGROUP_VICTIMS 1
#define OOM_TIMER_INTERVAL 2
@@ -105,6 +106,7 @@
#define MEM_SIZE_64 64 /* MB */
#define MEM_SIZE_256 256 /* MB */
#define MEM_SIZE_512 512 /* MB */
+#define MEM_SIZE_768 768 /* MB */
#define MEM_SIZE_1024 1024 /* MB */
#define MEM_SIZE_2048 2048 /* MB */
@@ -127,13 +129,23 @@
/* threshold for 512M RAM */
#define DYNAMIC_PROCESS_512_THRES 80 /* MB */
#define DYNAMIC_PROCESS_512_LEAVE 100 /* MB */
-#define DYNAMIC_PROCESS_512_THRESLAUNCH 60 /* MB */
-#define DYNAMIC_PROCESS_512_LEAVELAUNCH 80 /* MB */
+#define DYNAMIC_PROCESS_512_THRESLAUNCH 60 /* MB */
+#define DYNAMIC_PROCESS_512_LEAVELAUNCH 80 /* MB */
#define MEMCG_MEMORY_512_THRES_SWAP 100 /* MB */
#define MEMCG_MEMORY_512_THRES_LOW 50 /* MB */
#define MEMCG_MEMORY_512_THRES_MEDIUM 40 /* MB */
#define MEMCG_MEMORY_512_THRES_LEAVE 60 /* MB */
+/* threshold for 768 RAM */
+#define DYNAMIC_PROCESS_768_THRES 100 /* MB */
+#define DYNAMIC_PROCESS_768_LEAVE 120 /* MB */
+#define DYNAMIC_PROCESS_768_THRESLAUNCH 60 /* MB */
+#define DYNAMIC_PROCESS_768_LEAVELAUNCH 80 /* MB */
+#define MEMCG_MEMORY_768_THRES_SWAP 150 /* MB */
+#define MEMCG_MEMORY_768_THRES_LOW 100 /* MB */
+#define MEMCG_MEMORY_768_THRES_MEDIUM 60 /* MB */
+#define MEMCG_MEMORY_768_THRES_LEAVE 100 /* MB */
+
/* threshold for more than 1024M RAM */
#define DYNAMIC_PROCESS_1024_THRES 150 /* MB */
#define DYNAMIC_PROCESS_1024_LEAVE 300 /* MB */
@@ -150,7 +162,7 @@
#define MEMCG_MEMORY_2048_THRES_MEDIUM 160 /* MB */
#define MEMCG_MEMORY_2048_THRES_LEAVE 300 /* MB */
-static int thresholds[MEMNOTIFY_MAX_LEVELS];
+
static int dynamic_process_threshold[DYNAMIC_KILL_MAX];
static int dynamic_process_leave[DYNAMIC_KILL_MAX];
@@ -161,38 +173,19 @@ struct task_info {
int size;
};
-struct memcg_class {
- unsigned int min_limit; /* minimum limit */
- /* limit ratio, if don't want to set limit, use NO_LIMIT*/
- float limit_ratio;
- unsigned int oomleave; /* leave memory usage */
- char *cgroup_name; /* cgroup name */
- unsigned int thres_low; /* low level threshold */
- unsigned int thres_medium; /* medium level threshold */
- unsigned int thres_leave; /* leave threshold */
- /* vmpressure event string. If don't want to register event, use null */
- char *event_string;
- /* compare function for selecting victims in each cgroup */
- int (*compare_fn) (const struct task_info *, const struct task_info *);
-};
-
struct lowmem_process_entry {
int cur_mem_state;
int new_mem_state;
void (*action) (void);
};
-
struct victims {
int num;
pid_t pids[MAX_MEMORY_CGROUP_VICTIMS];
};
/* low memory action function for cgroup */
-static void memory_cgroup_medium_act(int memcg_idx);
-static int compare_mem_victims(const struct task_info *ta, const struct task_info *tb);
-static int compare_bg_victims(const struct task_info *ta, const struct task_info *tb);
-static int compare_fg_victims(const struct task_info *ta, const struct task_info *tb);
+static void memory_cgroup_medium_act(int idx, struct memcg_info_t *mi);
/* low memory action function */
static void normal_act(void);
static void swap_act(void);
@@ -202,7 +195,7 @@ static void medium_act(void);
static Eina_Bool medium_cb(void *data);
#define LOWMEM_ENTRY(c, n, act) \
- { MEMNOTIFY_##c, MEMNOTIFY_##n, act}
+ { LOWMEM_##c, LOWMEM_##n, act}
static struct lowmem_process_entry lpe[] = {
LOWMEM_ENTRY(NORMAL, SWAP, swap_act),
@@ -219,36 +212,7 @@ static struct lowmem_process_entry lpe[] = {
LOWMEM_ENTRY(MEDIUM, LOW, low_act),
};
-static struct memcg_class memcg_class[MEMCG_MAX_GROUPS] = {
- {NO_LIMIT, MEMCG_MEMORY_LIMIT_RATIO,
- 0, "memory",
- 0, 0,
- 0, "medium", /* register medium event*/
- compare_mem_victims},
- {MEMCG_FOREGROUND_MIN_LIMIT, MEMCG_FOREGROUND_LIMIT_RATIO,
- 0, "memory/foreground1",
- 0, 0,
- MEMCG_FOREGROUND_THRES_LEAVE, "medium",
- compare_fg_victims},
- {MEMCG_FOREGROUND_MIN_LIMIT, MEMCG_FOREGROUND_LIMIT_RATIO,
- 0, "memory/foreground2",
- 0, 0,
- MEMCG_FOREGROUND_THRES_LEAVE, "medium",
- compare_fg_victims},
- {MEMCG_FOREGROUND_MIN_LIMIT, MEMCG_FOREGROUND_LIMIT_RATIO,
- 0, "memory/foreground3",
- 0, 0,
- MEMCG_FOREGROUND_THRES_LEAVE, "medium",
- compare_fg_victims},
- {MEMCG_BACKGROUND_MIN_LIMIT, MEMCG_BACKGROUND_LIMIT_RATIO,
- 0, "memory/background",
- 0, 0,
- 0, NULL, /* register no event*/
- compare_bg_victims},
-};
-
-static int evfd[MEMCG_MAX_GROUPS] = {-1, };
-static int cur_mem_state = MEMNOTIFY_NORMAL;
+static int cur_mem_state = LOWMEM_NORMAL;
static Ecore_Timer *oom_check_timer = NULL;
static Ecore_Timer *oom_sigkill_timer = NULL;
static pid_t killed_fg_victim;
@@ -264,6 +228,17 @@ static unsigned long ktotalram;
static const struct module_ops memory_modules_ops;
static const struct module_ops *lowmem_ops;
+static char *memcg_name[MEMCG_MAX] = {
+ NULL,
+ "foreground",
+ "background",
+ "swap",
+};
+
+struct memcg_t **memcg;
+struct memcg_info_t *memcg_memory;
+
+static int compare_victims(const struct task_info *ta, const struct task_info *tb);
static inline void get_total_memory(void)
{
@@ -277,50 +252,6 @@ static inline void get_total_memory(void)
}
}
-unsigned int get_available(void)
-{
- char buf[PATH_MAX];
- FILE *fp;
- char *idx;
- unsigned int free = 0, cached = 0;
- unsigned int available = 0;
-
- fp = fopen(MEMINFO_PATH, "r");
-
- if (!fp) {
- _E("%s open failed, %d", buf, fp);
- return available;
- }
-
- while (fgets(buf, PATH_MAX, fp) != NULL) {
- if ((idx = strstr(buf, "MemFree:"))) {
- idx += strlen("MemFree:");
- while (*idx < '0' || *idx > '9')
- idx++;
- free = atoi(idx);
- } else if ((idx = strstr(buf, "MemAvailable:"))) {
- idx += strlen("MemAvailable:");
- while (*idx < '0' || *idx > '9')
- idx++;
- available = atoi(idx);
- break;
- } else if((idx = strstr(buf, "Cached:"))) {
- idx += strlen("Cached:");
- while (*idx < '0' || *idx > '9')
- idx++;
- cached = atoi(idx);
- break;
- }
- }
-
- if (available == 0)
- available = free + cached;
- available >>= 10;
- fclose(fp);
-
- return available;
-}
-
static bool get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
{
FILE *fp;
@@ -343,14 +274,14 @@ static bool get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
return true;
}
-static unsigned int get_mem_usage(int idx)
+unsigned int get_cgroup_mem_usage(const char *cgroup_name)
{
FILE *f;
- char buf[LOWMEM_PATH_MAX] = {0,};
+ char buf[MAX_PATH_LENGTH] = {0,};
unsigned int usage;
- sprintf(buf, "%s/%s/memory.usage_in_bytes",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
+ sprintf(buf, "%smemory.usage_in_bytes", cgroup_name);
+ _D("get mem usage from %s", buf);
f = fopen(buf, "r");
if (!f) {
@@ -368,16 +299,16 @@ static unsigned int get_mem_usage(int idx)
return usage;
}
-static int get_mem_usage_anon(int idx, unsigned int *result)
+static int get_mem_usage_anon(struct memcg_info_t *mi, unsigned int *result)
{
FILE *f;
- char buf[LOWMEM_PATH_MAX] = {0,};
+ char buf[BUF_MAX] = {0,};
char line[BUF_MAX] = {0, };
- char name[30] = {0, };
+ char name[BUF_MAX] = {0, };
unsigned int tmp, active_anon = 0, inactive_anon = 0;
- sprintf(buf, "%s/%s/memory.stat",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
+ sprintf(buf, "%smemory.stat", mi->name);
+ _I("get mem usage anon from %s", buf);
f = fopen(buf, "r");
if (!f) {
@@ -475,13 +406,13 @@ static void make_memps_log(char *file, pid_t pid, char *victim_name)
}
}
-static int lowmem_check_current_state(int memcg_index)
+static int lowmem_check_current_state(struct memcg_info_t *mi)
{
unsigned int usage, oomleave;
int ret;
- oomleave = memcg_class[memcg_index].oomleave;
- ret = get_mem_usage_anon(memcg_index, &usage);
+ oomleave = mi->oomleave;
+ ret = get_mem_usage_anon(mi, &usage);
if (ret) {
_D("getting anonymous usage fails");
@@ -499,77 +430,21 @@ static int lowmem_check_current_state(int memcg_index)
}
}
-static int compare_mem_victims(const struct task_info *ta, const struct task_info *tb)
-{
- int pa, pb;
- assert(ta != NULL);
- assert(tb != NULL);
-
- /*
- * Weight task size ratio to totalram by OOM_SCORE_POINT_WEIGHT so that
- * tasks with score -1000 or -900 could be selected as victims if they consumes
- * memory more than 70% of totalram.
- */
- pa = (int)(ta->size * OOM_SCORE_POINT_WEIGHT) / ktotalram + ta->oom_score_adj;
- pb = (int)(tb->size * OOM_SCORE_POINT_WEIGHT) / ktotalram + tb->oom_score_adj;
-
- return (pb - pa);
-}
-
-static int compare_bg_victims(const struct task_info *ta, const struct task_info *tb)
-{
- /*
- * Firstly, sort by oom_score_adj
- * Secondly, sort by task size
- */
- assert(ta != NULL);
- assert(tb != NULL);
-
- if (ta->oom_score_adj != tb->oom_score_adj)
- return (tb->oom_score_adj - ta->oom_score_adj);
-
- return ((int)(tb->size) - (int)(ta->size));
-}
-
-static int compare_fg_victims(const struct task_info *ta, const struct task_info *tb)
-{
- /*
- * only sort by task size
- */
- assert(ta != NULL);
- assert(tb != NULL);
-
- return ((int)(tb->size) - (int)(ta->size));
-}
-
-static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info *selected,
- unsigned should_be_freed, int flags)
+static int lowmem_get_pids_memcg(int idx, struct memcg_info_t *mi, GArray *pids)
{
+ char buf[BUF_MAX] = {0,};
+ char appname[BUF_MAX] = {0,};
FILE *f = NULL;
- char buf[LOWMEM_PATH_MAX] = {0, };
- int i = 0;
- int num_victims = 0;
- unsigned total_victim_size = 0;
- char appname[PATH_MAX] = {0, };
-
- GArray *victim_candidates = NULL;
-
- victim_candidates = g_array_new(false, false, sizeof(struct task_info));
-
- /* if g_array_new fails, return the current number of victims */
- if (victim_candidates == NULL)
- return num_victims;
+ int i;
if (idx == MEMCG_MEMORY) {
- sprintf(buf, "%s/%s/system.slice/cgroup.procs",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
+ sprintf(buf, "%ssystem.slice/cgroup.procs", mi->name);
f = fopen(buf, "r");
}
if (!f) {
- sprintf(buf, "%s/%s/cgroup.procs",
- MEMCG_PATH, memcg_class[idx].cgroup_name);
+ sprintf(buf, "%scgroup.procs", mi->name);
f = fopen(buf, "r");
if (!f) {
_E("%s open failed, %d", buf, f);
@@ -577,7 +452,7 @@ static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info
* if task read in this cgroup fails,
* return the current number of victims
*/
- return num_victims;
+ return pids->len;
}
}
@@ -602,8 +477,8 @@ static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info
if(proc_get_cmdline(tpid, appname) == RESOURCED_ERROR_FAIL)
continue;
- for (i = 0; i < victim_candidates->len; i++) {
- struct task_info *tsk = &g_array_index(victim_candidates,
+ for (i = 0; i < pids->len; i++) {
+ struct task_info *tsk = &g_array_index(pids,
struct task_info, i);
if (getpgid(tpid) == tsk->pgid) {
tsk->size += tsize;
@@ -615,28 +490,50 @@ static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info
}
}
- if (i == victim_candidates->len) {
+ if (i == pids->len) {
new_victim.pid = tpid;
new_victim.pgid = getpgid(tpid);
new_victim.oom_score_adj = toom;
new_victim.size = tsize;
- g_array_append_val(victim_candidates, new_victim);
+ g_array_append_val(pids, new_victim);
}
}
+ fclose(f);
+ return pids->len;
+
+}
+
+
+static int lowmem_get_cgroup_victims(int idx, struct memcg_info_t *mi,
+ int max_victims, struct task_info *selected,
+ unsigned should_be_freed, int flags)
+{
+ int i = 0;
+ int num_victims = 0;
+ unsigned total_victim_size = 0;
+ GArray *victim_candidates = NULL;
+ int count = 0;
+
+ victim_candidates = g_array_new(false, false, sizeof(struct task_info));
+
+ /* if g_array_new fails, return the current number of victims */
+ if (victim_candidates == NULL)
+ return num_victims;
+
/*
* if there is no tasks in this cgroup,
* return the current number of victims
*/
- if (victim_candidates->len == 0) {
+ count = lowmem_get_pids_memcg(idx, mi, victim_candidates);
+ if (count == 0) {
g_array_free(victim_candidates, true);
- fclose(f);
return num_victims;
}
g_array_sort(victim_candidates,
- (GCompareFunc)memcg_class[idx].compare_fn);
+ (GCompareFunc)compare_victims);
for (i = 0; i < victim_candidates->len; i++) {
struct task_info tsk;
@@ -648,16 +545,19 @@ static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info
tsk = g_array_index(victim_candidates, struct task_info, i);
- if (tsk.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED) {
+ if ((idx >= MEMCG_BACKGROUND) &&
+ (tsk.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED)) {
unsigned int available;
if ((flags & OOM_FORCE) || !(flags & OOM_TIMER_CHECK)) {
- _D("%d is skipped during force kill", tsk.pid);
+ _D("%d is skipped during force kill, flag = %d",
+ tsk.pid, flags);
break;
}
available = get_available();
if ((flags & OOM_TIMER_CHECK) &&
- (available > thresholds[MEMNOTIFY_MEDIUM] +
- THRESHOLD_MARGIN)) {
+ (available >
+ memcg_memory->threshold[LOWMEM_MEDIUM] +
+ THRESHOLD_MARGIN)) {
_D("available: %d MB, larger than threshold margin",
available);
break;
@@ -669,12 +569,12 @@ static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info
selected[num_victims].oom_score_adj = tsk.oom_score_adj;
selected[num_victims].size = tsk.size;
total_victim_size += tsk.size >> 10;
+ _D("selected[%d].pid = %d", num_victims, tsk.pid);
num_victims++;
}
g_array_free(victim_candidates, true);
- fclose(f);
return num_victims;
}
@@ -688,17 +588,17 @@ static int lowmem_swap_cgroup_oom_killer(int flags)
int ret;
char appname[PATH_MAX];
int count = 0;
- char buf[LOWMEM_PATH_MAX] = {0, };
+ char buf[BUF_MAX] = {0, };
FILE *f;
unsigned int tsize = 0;
- int swap_type;
+ const char *name;
- swap_type = swap_status(SWAP_GET_TYPE, NULL);
- if (swap_type <= SWAP_OFF)
- return count;
+ if (!memcg[MEMCG_SWAP] || !memcg[MEMCG_SWAP]->info)
+ return RESOURCED_ERROR_FAIL;
- sprintf(buf, "%s/memory/swap/cgroup.procs",
- MEMCG_PATH);
+ name = memcg[MEMCG_SWAP]->info->name;
+
+ sprintf(buf, "%scgroup.procs", name);
f = fopen(buf, "r");
if (!f) {
@@ -722,7 +622,6 @@ static int lowmem_swap_cgroup_oom_killer(int flags)
continue;
}
- /* To Do: skip by checking pgid? */
if (toom < OOMADJ_BACKGRD_UNLOCKED)
continue;
@@ -730,15 +629,15 @@ static int lowmem_swap_cgroup_oom_killer(int flags)
if (ret == RESOURCED_ERROR_FAIL)
continue;
- /* make memps log for killing application firstly */
if (count == 0)
make_memps_log(MEMPS_LOG_FILE, tpid, appname);
count++;
- proc_remove_process_list(tpid);
kill(tpid, SIGKILL);
- _E("we killed, lowmem lv2 = %d (%s) score = %d, size = %u KB\n",
+
+ proc_remove_process_list(tpid);
+ _E("we killed, %d (%s) score = %d, size = %u KB\n",
tpid, appname, toom, tsize);
if (is_dynamic_process_killer(flags) &&
count >= MAX_SWAP_VICTIMS)
@@ -754,68 +653,137 @@ static int lowmem_swap_cgroup_oom_killer(int flags)
return count;
}
+static int lowmem_get_subcgroup_victims(int idx, struct task_info *selected,
+ int max_victims, int flags)
+{
+ GSList *iter = NULL;
+ GArray *pids = NULL;
+ int num_victims, count;
+ unsigned int total_victim_size = 0;
+ unsigned int available;
+
+ pids = g_array_new(false, false, sizeof(struct task_info));
+ gslist_for_each_item(iter, memcg[idx]->cgroups) {
+ struct memcg_info_t *mi =
+ (struct memcg_info_t *)(iter->data);
+ count = lowmem_get_pids_memcg(idx, mi, pids);
+ _D("get %d pids", count);
+ }
+
+ g_array_sort(pids, (GCompareFunc)compare_victims);
+
+ for (num_victims = 0; num_victims < pids->len; num_victims++) {
+ struct task_info tsk;
+ if (num_victims == max_victims)
+ break;
+
+ tsk = g_array_index(pids, struct task_info, num_victims);
+
+ if ((idx >= MEMCG_BACKGROUND) &&
+ (tsk.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED)) {
+ if ((flags & OOM_FORCE) || !(flags & OOM_TIMER_CHECK)) {
+ _D("%d is skipped during force kill, flag = %d",
+ tsk.pid, flags);
+ break;
+ }
+ available = get_available();
+ if ((flags & OOM_TIMER_CHECK) &&
+ (available >
+ memcg_memory->threshold[LOWMEM_MEDIUM] +
+ THRESHOLD_MARGIN)) {
+ _D("available: %d MB, larger than threshold margin",
+ available);
+ break;
+ }
+ }
+
+ selected[num_victims].pid = tsk.pid;
+ selected[num_victims].pgid = tsk.pgid;
+ selected[num_victims].oom_score_adj = tsk.oom_score_adj;
+ selected[num_victims].size = tsk.size;
+ total_victim_size += tsk.size >> 10;
+ _D("selected[%d].pid = %d, total size = %u", num_victims, tsk.pid, total_victim_size);
+ }
+
+ g_array_free(pids, true);
+ return num_victims;
+}
+
/* Find victims: (SWAP -> ) BACKGROUND */
-static int lowmem_get_memory_cgroup_victims(struct task_info *selected,
- int flags)
+static int lowmem_get_memory_cgroup_victims(struct task_info *selected, int flags)
{
int i, swap_victims, count = 0;
- unsigned int available, should_be_freed = 0;
+ unsigned int available, should_be_freed = 0, leave_threshold;
+ struct memcg_info_t *mi;
+ unsigned int threshold;
+ /* To Do: swap cgroup will be treated like other cgroups */
swap_victims = lowmem_swap_cgroup_oom_killer(flags);
if ((flags & OOM_FORCE) && swap_victims < MAX_FD_VICTIMS) {
count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
- MAX_FD_VICTIMS - swap_victims, selected,
- 0, flags);
- _D("kill %d victims in %s cgroup",
- count, memcg_class[MEMCG_BACKGROUND].cgroup_name);
+ memcg[MEMCG_BACKGROUND]->info,
+ MAX_FD_VICTIMS - swap_victims,
+ selected, 0, flags);
+ _D("kill %d victims in background cgroup", count);
return count;
}
available = get_available();
- if (available < memcg_class[MEMCG_MEMORY].thres_leave)
- should_be_freed = memcg_class[MEMCG_MEMORY].thres_leave - available;
+ leave_threshold = memcg_memory->threshold_leave;
+ if (available < leave_threshold)
+ should_be_freed = leave_threshold - available;
_I("should_be_freed = %u MB", should_be_freed);
if (should_be_freed == 0 || swap_victims >= num_max_victims)
return count;
- for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
- if ((flags & OOM_TIMER_CHECK) && i < MEMCG_BACKGROUND &&
- available > thresholds[MEMNOTIFY_MEDIUM]) {
+ for (i = MEMCG_MAX - 1; i >= 0; i--) {
+ if (!memcg[i] || !memcg[i]->info)
+ continue;
+ mi = memcg[i]->info;
+ threshold = mi->threshold[LOWMEM_MEDIUM];
+
+ if ((flags & OOM_TIMER_CHECK) && (i < MEMCG_BACKGROUND) &&
+ (available > threshold)) {
_D("in timer, not kill fg app, available %u > threshold %u",
- available, thresholds[MEMNOTIFY_MEDIUM]);
+ available, threshold);
return count;
}
- count = lowmem_get_cgroup_victims(i,
- num_max_victims - swap_victims,
- selected, should_be_freed, flags);
+ if (!memcg[i]->use_hierarchy)
+ count = lowmem_get_cgroup_victims(i, mi,
+ num_max_victims - swap_victims,
+ selected, should_be_freed, flags);
+ else
+ /* To Do: include max num victims in memcg_t and use it */
+ count = lowmem_get_subcgroup_victims(i, selected,
+ num_max_victims, flags);
if (count > 0) {
- _D("kill %d victims in %s cgroup",
- count, memcg_class[i].cgroup_name);
+ _D("get %d victims in %s cgroup", count,
+ mi->name);
return count;
} else
_D("There are no victims to be killed in %s cgroup",
- memcg_class[i].cgroup_name);
+ mi->name);
}
return count;
}
-static int lowmem_get_victims(int idx, struct task_info *selected,
- int flags)
+static int lowmem_get_victims(int idx, struct memcg_info_t *mi,
+ struct task_info *selected, int flags)
{
int count = 0;
if (idx == MEMCG_MEMORY)
count = lowmem_get_memory_cgroup_victims(selected, flags);
else
- count = lowmem_get_cgroup_victims(idx,
- MAX_CGROUP_VICTIMS, selected,
- memcg_class[idx].thres_leave,
- flags);
+ count = lowmem_get_cgroup_victims(idx, mi,
+ MAX_CGROUP_VICTIMS, selected,
+ mi->threshold_leave,
+ flags);
return count;
}
@@ -845,13 +813,10 @@ static int lowmem_kill_victims(int memcg_idx,
int pid, ret, oom_score_adj, i;
unsigned total_size = 0, size;
char appname[PATH_MAX];
+ int sigterm = 0;
+ int app_flag = 0;
for (i = 0; i < count; i++) {
- /* check current memory status */
- if (!(flags & OOM_FORCE) && memcg_idx != MEMCG_MEMORY &&
- lowmem_check_current_state(memcg_idx) >= 0)
- return count;
-
pid = selected[i].pid;
oom_score_adj = selected[i].oom_score_adj;
size = selected[i].size;
@@ -877,16 +842,24 @@ static int lowmem_kill_victims(int memcg_idx,
total_size += size;
- proc_remove_process_list(pid);
- if (flags & OOM_FORCE) {
+ if (oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
+ sigterm = 1;
+ } else if (oom_score_adj == OOMADJ_BACKGRD_LOCKED) {
+ app_flag = proc_get_apptype(pid);
+ sigterm = app_flag & PROC_SIGTERM;
+ }
+
+ if (sigterm) {
kill(pid, SIGTERM);
if (killed_tasks.num < MAX_MEMORY_CGROUP_VICTIMS)
killed_tasks.pids[killed_tasks.num++] = pid;
} else
kill(pid, SIGKILL);
- _E("we killed, force(%d), lowmem lv2 = %d (%s) score = %d, size = %u KB, victim total size = %u KB\n",
- flags & OOM_FORCE, pid, appname, oom_score_adj, size, total_size);
+ proc_remove_process_list(pid);
+ _E("we killed, force(%d), %d (%s) score = %d, size = %u KB, victim total size = %u KB, sigterm = %d\n",
+ flags & OOM_FORCE, pid, appname, oom_score_adj,
+ size, total_size, sigterm);
if (memcg_idx >= MEMCG_FOREGROUND &&
memcg_idx < MEMCG_BACKGROUND)
@@ -902,27 +875,45 @@ static int lowmem_kill_victims(int memcg_idx,
return count;
}
-int lowmem_oom_killer_cb(int memcg_idx, int flags)
+static int lowmem_oom_killer_cb(int idx, struct memcg_info_t *mi, int flags)
{
struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
int count = 0;
/* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
- count = lowmem_get_victims(memcg_idx, selected, flags);
+ count = lowmem_get_victims(idx, mi, selected, flags);
if (count == 0) {
- _D("get %s cgroup victim is failed",
- memcg_class[memcg_idx].cgroup_name);
+ _D("victim count = %d", count);
return count;
}
- count = lowmem_kill_victims(memcg_idx, count, selected, flags);
+ /* check current memory status */
+ if (!(flags & OOM_FORCE) && idx != MEMCG_MEMORY &&
+ lowmem_check_current_state(mi) >= 0)
+ return count;
+
+
+ count = lowmem_kill_victims(idx, count, selected, flags);
clear_logs(MEMPS_LOG_PATH);
logging_control(LOGGING_UPDATE_STATE, NULL);
+ if (killed_tasks.num > 0 && oom_sigkill_timer == NULL) {
+ _D("start timer to sigkill tasks");
+ oom_sigkill_timer =
+ ecore_timer_add(OOM_SIGKILL_WAIT, send_sigkill_cb,
+ NULL);
+ } else
+ killed_tasks.num = 0;
+
return count;
}
+int lowmem_memory_oom_killer(int flags)
+{
+ return lowmem_oom_killer_cb(MEMCG_MEMORY, memcg_memory, flags);
+}
+
void lowmem_dynamic_process_killer(int type)
{
struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
@@ -931,6 +922,7 @@ void lowmem_dynamic_process_killer(int type)
unsigned should_be_freed;
int flags = OOM_FORCE;
int swap_victims;
+ struct memcg_info_t *mi = memcg[MEMCG_BACKGROUND]->info;
if (!dynamic_process_threshold[type])
return;
@@ -938,7 +930,7 @@ void lowmem_dynamic_process_killer(int type)
if (available >= dynamic_process_threshold[type])
return;
- change_memory_state(MEMNOTIFY_LOW, 1);
+ change_memory_state(LOWMEM_LOW, 1);
swap_victims = lowmem_swap_cgroup_oom_killer(flags);
if (swap_victims >= MAX_SWAP_VICTIMS)
goto start_timer;
@@ -949,7 +941,7 @@ void lowmem_dynamic_process_killer(int type)
should_be_freed = dynamic_process_leave[type] - available;
_D("run dynamic killer, type=%d, available=%d, should_be_freed = %u", type, available, should_be_freed);
- count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
+ count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND, mi,
num_max_victims - swap_victims, selected,
should_be_freed, flags);
@@ -959,7 +951,7 @@ void lowmem_dynamic_process_killer(int type)
}
lowmem_kill_victims(MEMCG_BACKGROUND, count, selected, flags);
- change_memory_state(MEMNOTIFY_NORMAL, 0);
+ change_memory_state(LOWMEM_NORMAL, 0);
start_timer:
if (oom_sigkill_timer == NULL) {
@@ -996,7 +988,7 @@ static void *lowmem_oom_killer_pthread(void *arg)
}
_I("oom thread conditional signal received and start");
- lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_NONE);
+ lowmem_oom_killer_cb(MEMCG_MEMORY, memcg_memory, OOM_NONE);
_I("lowmem_oom_killer_cb finished");
ret = pthread_mutex_unlock(&oom_mutex);
@@ -1016,16 +1008,16 @@ static char *convert_to_str(int mem_state)
{
char *tmp = NULL;
switch (mem_state) {
- case MEMNOTIFY_NORMAL:
+ case LOWMEM_NORMAL:
tmp = "mem normal";
break;
- case MEMNOTIFY_SWAP:
+ case LOWMEM_SWAP:
tmp = "mem swap";
break;
- case MEMNOTIFY_LOW:
+ case LOWMEM_LOW:
tmp = "mem low";
break;
- case MEMNOTIFY_MEDIUM:
+ case LOWMEM_MEDIUM:
tmp = "mem medium";
break;
default:
@@ -1046,27 +1038,10 @@ static void change_lowmem_state(unsigned int mem_state)
static void lowmem_swap_memory(void)
{
- pid_t pid;
- int swap_type;
-
- if (cur_mem_state == MEMNOTIFY_NORMAL)
+ if (cur_mem_state == LOWMEM_NORMAL)
return;
- swap_type = swap_status(SWAP_GET_TYPE, NULL);
-
- if (swap_type == SWAP_ON) {
- while (1)
- {
- pid = (pid_t)swap_status(SWAP_GET_CANDIDATE_PID, NULL);
- if (!pid)
- break;
- _I("swap cgroup entered : pid : %d", (int)pid);
- resourced_notify(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, (void*)&pid);
- }
- if (swap_status(SWAP_GET_STATUS, NULL) == SWAP_OFF)
- resourced_notify(RESOURCED_NOTIFIER_SWAP_RESTART, NULL);
- resourced_notify(RESOURCED_NOTIFIER_SWAP_START, NULL);
- }
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_START, NULL);
}
@@ -1077,11 +1052,13 @@ static void normal_act(void)
ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
if (ret)
_D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
- if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL)
+ if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+ memory_level_send_system_event(MEMORY_LEVEL_NORMAL);
+ }
- change_lowmem_state(MEMNOTIFY_NORMAL);
+ change_lowmem_state(LOWMEM_NORMAL);
}
static void swap_act(void)
@@ -1092,10 +1069,12 @@ static void swap_act(void)
if (ret)
_E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
- if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL)
+ if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
- change_lowmem_state(MEMNOTIFY_SWAP);
+ memory_level_send_system_event(MEMORY_LEVEL_NORMAL);
+ }
+ change_lowmem_state(LOWMEM_SWAP);
}
static void low_act(void)
@@ -1107,25 +1086,27 @@ static void low_act(void)
if (ret)
_D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
- change_lowmem_state(MEMNOTIFY_LOW);
+ change_lowmem_state(LOWMEM_LOW);
/* Since vconf for soft warning could be set during low memory check,
* we set it only when the current status is not soft warning.
*/
- if (status != VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
+ if (status != VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING);
+ memory_level_send_system_event(MEMORY_LEVEL_LOW);
+ }
}
static Eina_Bool medium_cb(void *data)
{
- unsigned int available;
+ unsigned int available, threshold;
int count = 0;
available = get_available();
_D("available = %u, timer run until reaching leave threshold", available);
- if (available >= memcg_class[MEMCG_MEMORY].thres_leave && oom_check_timer != NULL) {
+ if (available >= memcg_memory->threshold_leave && oom_check_timer != NULL) {
ecore_timer_del(oom_check_timer);
oom_check_timer = NULL;
_D("oom_check_timer deleted after reaching leave threshold");
@@ -1134,18 +1115,20 @@ static Eina_Bool medium_cb(void *data)
}
_I("cannot reach leave threshold, timer again");
- count = lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_TIMER_CHECK);
+ count = lowmem_oom_killer_cb(MEMCG_MEMORY,
+ memcg_memory, OOM_TIMER_CHECK);
/*
* After running oom killer in timer, but there is no victim,
* stop timer.
*/
- if (!count && available >= thresholds[MEMNOTIFY_MEDIUM] &&
+ threshold = memcg_memory->threshold[LOWMEM_MEDIUM];
+ if (!count && available >= threshold &&
oom_check_timer != NULL) {
ecore_timer_del(oom_check_timer);
oom_check_timer = NULL;
_D("oom_check_timer deleted, available %u > threshold %u",
- available, thresholds[MEMNOTIFY_MEDIUM]);
+ available, threshold);
normal_act();
return ECORE_CALLBACK_CANCEL;
}
@@ -1156,7 +1139,7 @@ static void medium_act(void)
{
int ret = 0;
- change_lowmem_state(MEMNOTIFY_MEDIUM);
+ change_lowmem_state(LOWMEM_MEDIUM);
/* signal to lowmem_oom_killer_pthread to start killer */
ret = pthread_mutex_trylock(&oom_mutex);
@@ -1171,6 +1154,7 @@ static void medium_act(void)
vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
+ memory_level_send_system_event(MEMORY_LEVEL_CRITICAL);
if (oom_check_timer == NULL) {
_D("timer run until reaching leave threshold");
@@ -1198,54 +1182,14 @@ static int lowmem_process(int mem_state)
return RESOURCED_ERROR_NONE;
}
-static bool is_fg_victim_killed(int memcg_idx)
-{
- if (killed_fg_victim) {
- char buf[LOWMEM_PATH_MAX] = {0, };
- FILE *f;
- sprintf(buf, "%s/memory/foreground%d/cgroup.procs", MEMCG_PATH,
- memcg_idx);
- f = fopen(buf, "r");
- if (!f) {
- _E("%s open failed, %d", buf, f);
- /* if file open fails, start to kill */
- return true;
- }
-
- while (fgets(buf, 32, f) != NULL) {
- pid_t pid = atoi(buf);
-
- /*
- * not yet removed from foreground cgroup,
- * so, not start to kill again
- */
- if (killed_fg_victim == pid) {
- fclose(f);
- return false;
- }
- }
-
- /*
- * in this case, memory is low even though the previous
- * fg victim was already killed. so, start to kill.
- */
- fclose(f);
- killed_fg_victim = 0;
- return true;
- }
-
- return true;
-}
-
-static void show_foreground_procs(int memcg_idx) {
- char buf[LOWMEM_PATH_MAX] = {0, };
+static void show_foreground_procs(struct memcg_info_t *mi) {
+ char buf[BUF_MAX] = {0, };
FILE *f;
- sprintf(buf, "%s/memory/foreground%d/cgroup.procs", MEMCG_PATH,
- memcg_idx);
+ sprintf(buf, "%scgroup.procs", mi->name);
+
f = fopen(buf, "r");
if (!f) {
_E("%s open failed, %d", buf, f);
- /* if file open fails, start to kill */
return;
}
@@ -1259,17 +1203,14 @@ static void show_foreground_procs(int memcg_idx) {
fclose(f);
}
-static void memory_cgroup_medium_act(int memcg_idx)
+static void memory_cgroup_medium_act(int idx, struct memcg_info_t *mi)
{
_I("[LOW MEM STATE] memory cgroup %s oom state",
- memcg_class[memcg_idx].cgroup_name);
+ mi->name);
- /* only start to kill fg victim when no pending fg victim */
- if ((memcg_idx >= MEMCG_FOREGROUND && memcg_idx < MEMCG_BACKGROUND)
- && is_fg_victim_killed(memcg_idx)) {
- show_foreground_procs(memcg_idx);
- lowmem_oom_killer_cb(memcg_idx, OOM_NONE);
- }
+ /* To Do: only start to kill fg victim when no pending fg victim */
+ show_foreground_procs(mi);
+ lowmem_oom_killer_cb(idx, mi, OOM_NONE);
}
static unsigned int lowmem_eventfd_read(int fd)
@@ -1283,8 +1224,8 @@ static unsigned int lowmem_eventfd_read(int fd)
static unsigned int check_mem_state(unsigned int available)
{
int mem_state;
- for (mem_state = MEMNOTIFY_MAX_LEVELS -1; mem_state > MEMNOTIFY_NORMAL; mem_state--) {
- if (available <= thresholds[mem_state])
+ for (mem_state = LOWMEM_MAX_LEVEL -1; mem_state > LOWMEM_NORMAL; mem_state--) {
+ if (available <= memcg_memory->threshold[mem_state])
break;
}
@@ -1305,16 +1246,16 @@ void change_memory_state(int state, int force)
}
switch (mem_state) {
- case MEMNOTIFY_NORMAL:
+ case LOWMEM_NORMAL:
normal_act();
break;
- case MEMNOTIFY_SWAP:
+ case LOWMEM_SWAP:
swap_act();
break;
- case MEMNOTIFY_LOW:
+ case LOWMEM_LOW:
low_act();
break;
- case MEMNOTIFY_MEDIUM:
+ case LOWMEM_MEDIUM:
medium_act();
break;
default:
@@ -1322,7 +1263,7 @@ void change_memory_state(int state, int force)
}
}
-static void lowmem_handler(void)
+static void lowmem_memory_handler(void)
{
static unsigned int prev_available;
unsigned int available;
@@ -1338,28 +1279,30 @@ static void lowmem_handler(void)
prev_available = available;
}
-static void lowmem_cgroup_handler(int memcg_idx)
+static void lowmem_cgroup_handler(int idx, struct memcg_info_t *mi)
{
- unsigned int usage;
+ unsigned int usage, threshold;
int ret;
- ret = get_mem_usage_anon(memcg_idx, &usage);
+ ret = get_mem_usage_anon(mi, &usage);
if (ret) {
_D("getting anonymous memory usage fails");
return;
}
-
- if (usage >= memcg_class[memcg_idx].thres_medium)
- memory_cgroup_medium_act(memcg_idx);
+ threshold = mi->threshold[LOWMEM_MEDIUM];
+ if (usage >= threshold)
+ memory_cgroup_medium_act(idx, mi);
else
_I("anon page (%u) is under medium threshold (%u)",
- usage >> 20, memcg_class[memcg_idx].thres_medium >> 20);
+ usage >> 20, threshold >> 20);
}
static Eina_Bool lowmem_cb(void *data, Ecore_Fd_Handler *fd_handler)
{
int fd, i;
+ struct memcg_info_t *mi;
+ GSList *iter = NULL;
if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
_E("ecore_main_fd_handler_active_get error , return\n");
@@ -1373,12 +1316,26 @@ static Eina_Bool lowmem_cb(void *data, Ecore_Fd_Handler *fd_handler)
}
lowmem_eventfd_read(fd);
- for (i = 0; i < MEMCG_MAX_GROUPS; i++) {
- if (fd == evfd[i]) {
- if (i == MEMCG_MEMORY) {
- lowmem_handler();
- } else {
- lowmem_cgroup_handler(i);
+ for (i = 0; i < MEMCG_MAX; i++) {
+ if (!memcg[i] || !memcg[i]->info)
+ continue;
+ mi = memcg[i]->info;
+ if (fd == mi->evfd) {
+ /* call low memory handler for this memcg */
+ if (i == MEMCG_MEMORY)
+ lowmem_memory_handler();
+ else
+ lowmem_cgroup_handler(i, mi);
+ return ECORE_CALLBACK_RENEW;
+ }
+ /* ToDo: iterate child memcgs */
+ gslist_for_each_item(iter, memcg[i]->cgroups) {
+ mi = (struct memcg_info_t *)(iter->data);
+ if (fd == mi->evfd) {
+ lowmem_cgroup_handler(i, mi);
+ _D("lowmem cgroup handler is called for %s",
+ mi->name);
+ return ECORE_CALLBACK_RENEW;
}
}
}
@@ -1395,115 +1352,84 @@ To register a notifier, application need:
to cgroup.event_control
*/
-static int setup_eventfd(void)
+static void register_eventfd(struct memcg_info_t *mi)
{
- unsigned int i;
- int cgfd, pressurefd, res, sz;
- char buf[LOWMEM_PATH_MAX] = {0,};
-
-
- for (i = 0; i < MEMCG_MAX_GROUPS; i++) {
- if (memcg_class[i].event_string == NULL)
- continue;
- /* open cgroup.event_control */
- sprintf(buf, "%s/%s/cgroup.event_control",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- cgfd = open(buf, O_WRONLY);
- if (cgfd < 0) {
- _E("open event_control failed");
- return RESOURCED_ERROR_FAIL;
- }
-
- /* register event pressure_level */
- sprintf(buf, "%s/%s/memory.pressure_level",
- MEMCG_PATH, memcg_class[i].cgroup_name);
- pressurefd = open(buf, O_RDONLY);
- if (pressurefd < 0) {
- _E("open pressure control failed");
- close(cgfd);
- return RESOURCED_ERROR_FAIL;
- }
+ int cgfd, pressurefd, evfd, res, sz;
+ char buf[BUF_MAX] = {0,};
+ const char *name = mi->name;
- /* create an eventfd using eventfd(2)
- use same event fd for using ecore event loop */
- evfd[i] = eventfd(0, O_NONBLOCK);
- if (evfd[i] < 0) {
- _E("eventfd() error");
- close(cgfd);
- close(pressurefd);
- return RESOURCED_ERROR_FAIL;
- }
-
- /* pressure level*/
- /* write event fd low level */
- sz = sprintf(buf, "%d %d %s", evfd[i], pressurefd,
- memcg_class[i].event_string);
- sz += 1;
- res = write(cgfd, buf, sz);
- if (res != sz) {
- _E("write cgfd failed : %d for %s",
- res, memcg_class[i].cgroup_name);
- close(cgfd);
- close(pressurefd);
- close(evfd[i]);
- evfd[i] = -1;
- return RESOURCED_ERROR_FAIL;
- }
+ if (mi->threshold[LOWMEM_MEDIUM] == LOWMEM_THRES_INIT)
+ return;
- _I("register event fd success for %s cgroup",
- memcg_class[i].cgroup_name);
- ecore_main_fd_handler_add(evfd[i], ECORE_FD_READ,
- (Ecore_Fd_Cb)lowmem_cb, NULL, NULL, NULL);
+ /* open cgroup.event_control */
+ sprintf(buf, "%scgroup.event_control", name);
+ cgfd = open(buf, O_WRONLY);
+ if (cgfd < 0) {
+ _E("open event_control failed");
+ return;
+ }
+ /* register event pressure_level */
+ sprintf(buf, "%smemory.pressure_level", name);
+ pressurefd = open(buf, O_RDONLY);
+ if (pressurefd < 0) {
+ _E("open pressure control failed");
close(cgfd);
- close(pressurefd);
+ return;
}
- return 0;
-}
-
-static int write_cgroup_node(const char *memcg_name,
- const char *file_name, unsigned int value)
-{
- FILE *f = NULL;
- char buf[LOWMEM_PATH_MAX] = {0, };
- int size;
- sprintf(buf, "%s/%s/%s", MEMCG_PATH, memcg_name, file_name);
- f = fopen(buf, "w");
- if (!f) {
- _E("%s open failed", buf);
- return RESOURCED_ERROR_FAIL;
+ /* create an eventfd using eventfd(2)
+ use same event fd for using ecore event loop */
+ evfd = eventfd(0, O_NONBLOCK);
+ if (evfd < 0) {
+ _E("eventfd() error");
+ close(cgfd);
+ close(pressurefd);
+ return;
}
+ mi->evfd = evfd;
- size = sprintf(buf, "%u", value);
- if (fwrite(buf, size, 1, f) != 1) {
- _E("fail fwrite %s\n", file_name);
- fclose(f);
- return RESOURCED_ERROR_FAIL;
+ /* pressure level*/
+ /* write event fd low level */
+ sz = sprintf(buf, "%d %d %s", evfd, pressurefd, mi->event_level);
+ sz += 1;
+ res = write(cgfd, buf, sz);
+ if (res != sz) {
+ _E("write cgfd failed : %d for %s", res, name);
+ close(cgfd);
+ close(pressurefd);
+ close(evfd);
+ mi->evfd = -1;
+ return;
}
- fclose(f);
- return RESOURCED_ERROR_NONE;
-}
+ _I("register event fd success for %s cgroup", name);
+ ecore_main_fd_handler_add(evfd, ECORE_FD_READ,
+ (Ecore_Fd_Cb)lowmem_cb, NULL, NULL, NULL);
-void set_threshold(int level, int thres)
-{
- thresholds[level] = thres;
+ close(cgfd);
+ close(pressurefd);
return;
}
-void set_leave_threshold(int thres)
+static int setup_eventfd(void)
{
- memcg_class[MEMCG_MEMORY].thres_leave = thres;
- return;
-}
+ unsigned int i;
+ struct memcg_info_t *mi;
+ GSList *iter = NULL;
-void set_foreground_ratio(float ratio)
-{
- int i;
- for (i = MEMCG_FOREGROUND; i < MEMCG_BACKGROUND; i++)
- memcg_class[i].limit_ratio = ratio;
- return;
+ for (i = 0; i < MEMCG_MAX; i++) {
+ if (!memcg[i]->use_hierarchy) {
+ register_eventfd(memcg[i]->info);
+ } else {
+ GSList *list = memcg[i]->cgroups;
+ gslist_for_each_item(iter, list) {
+ mi = (struct memcg_info_t *)(iter->data);
+ register_eventfd(mi);
+ }
+ }
+ }
+ return RESOURCED_ERROR_NONE;
}
static int load_mem_config(struct parse_result *result, void *user_data)
@@ -1523,6 +1449,17 @@ static int load_mem_config(struct parse_result *result, void *user_data)
return RESOURCED_ERROR_NONE;
}
+void lowmem_memcg_set_threshold(int idx, int level, int value)
+{
+ memcg[idx]->info->threshold[level] = value;
+}
+
+void lowmem_memcg_set_leave_threshold(int idx, int value)
+{
+ memcg[idx]->info->threshold_leave = value;
+}
+
+
static int set_memory_config(const char * section_name, const struct parse_result *result)
{
if (!result || !section_name)
@@ -1533,19 +1470,27 @@ static int set_memory_config(const char * section_name, const struct parse_resul
if (!strcmp(result->name, "ThresholdSwap")) {
int value = atoi(result->value);
- set_threshold(MEMNOTIFY_SWAP, value);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, value);
} else if (!strcmp(result->name, "ThresholdLow")) {
int value = atoi(result->value);
- set_threshold(MEMNOTIFY_LOW, value);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, value);
} else if (!strcmp(result->name, "ThresholdMedium")) {
int value = atoi(result->value);
- set_threshold(MEMNOTIFY_MEDIUM, value);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, value);
} else if (!strcmp(result->name, "ThresholdLeave")) {
int value = atoi(result->value);
- set_leave_threshold(value);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, value);
} else if (!strcmp(result->name, "ForegroundRatio")) {
- float value = atof(result->value);
- set_foreground_ratio(value);
+ float ratio = atof(result->value);
+ memcg_info_set_limit(memcg[MEMCG_FOREGROUND]->info, ratio, totalram);
+ } else if (!strcmp(result->name, "ForegroundUseHierarchy")) {
+ int use_hierarchy = atoi(result->value);
+ memcg[MEMCG_FOREGROUND]->use_hierarchy = use_hierarchy;
+ } else if (!strcmp(result->name, "ForegroundNumCgroups")) {
+ int num_cgroups = atoi(result->value);
+ memcg_add_cgroups(memcg[MEMCG_FOREGROUND],
+ num_cgroups);
+ memcg_show(memcg[MEMCG_FOREGROUND]);
} else if (!strcmp(result->name, "NumMaxVictims")) {
int value = atoi(result->value);
num_max_victims = value;
@@ -1589,6 +1534,11 @@ static int memory_load_512_config(struct parse_result *result, void *user_data)
return set_memory_config("Memory512", result);
}
+static int memory_load_768_config(struct parse_result *result, void *user_data)
+{
+ return set_memory_config("Memory768", result);
+}
+
static int memory_load_1024_config(struct parse_result *result, void *user_data)
{
return set_memory_config("Memory1024", result);
@@ -1599,30 +1549,29 @@ static int memory_load_2048_config(struct parse_result *result, void *user_data)
return set_memory_config("Memory2048", result);
}
-/* init thresholds depending on total ram size. */
-static void init_thresholds(void)
+/* setup memcg parameters depending on total ram size. */
+static void setup_memcg_params(void)
{
int i;
unsigned long total_ramsize = BtoMB(totalram);
_D("Total : %lu MB", total_ramsize);
-
if (total_ramsize <= MEM_SIZE_64) {
/* set thresholds for ram size 64M */
dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_THRES;
dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_LEAVE;
- set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_64_THRES_SWAP);
- set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_64_THRES_LOW);
- set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_64_THRES_MEDIUM);
- set_leave_threshold(MEMCG_MEMORY_64_THRES_LEAVE);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_64_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_64_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_64_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_64_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_64_config, NULL);
} else if (total_ramsize <= MEM_SIZE_256) {
/* set thresholds for ram size 256M */
dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_THRES;
dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_LEAVE;
- set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_256_THRES_SWAP);
- set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_256_THRES_LOW);
- set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_256_THRES_MEDIUM);
- set_leave_threshold(MEMCG_MEMORY_256_THRES_LEAVE);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_256_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_256_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_256_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_256_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_256_config, NULL);
} else if (total_ramsize <= MEM_SIZE_512) {
/* set thresholds for ram size 512M */
@@ -1630,101 +1579,160 @@ static void init_thresholds(void)
dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_LEAVE;
dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_THRESLAUNCH;
dynamic_process_leave[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_LEAVELAUNCH;
- set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_512_THRES_SWAP);
- set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_512_THRES_LOW);
- set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_512_THRES_MEDIUM);
- set_leave_threshold(MEMCG_MEMORY_512_THRES_LEAVE);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_512_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_512_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_512_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_512_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_512_config, NULL);
+ } else if (total_ramsize <= MEM_SIZE_768) {
+ /* set thresholds for ram size 512M */
+ dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_768_THRES;
+ dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_768_LEAVE;
+ dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_768_THRESLAUNCH;
+ dynamic_process_leave[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_768_LEAVELAUNCH;
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_768_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_768_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_768_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_768_THRES_LEAVE);
+ config_parse(MEM_CONF_FILE, memory_load_768_config, NULL);
} else if (total_ramsize <= MEM_SIZE_1024) {
/* set thresholds for ram size more than 1G */
dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_THRES;
dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_LEAVE;
- set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_1024_THRES_SWAP);
- set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_1024_THRES_LOW);
- set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_1024_THRES_MEDIUM);
- set_leave_threshold(MEMCG_MEMORY_1024_THRES_LEAVE);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_1024_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_1024_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_1024_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_1024_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_1024_config, NULL);
} else {
dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_THRES;
dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_LEAVE;
- set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_2048_THRES_SWAP);
- set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_2048_THRES_LOW);
- set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_2048_THRES_MEDIUM);
- set_leave_threshold(MEMCG_MEMORY_2048_THRES_LEAVE);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_SWAP, MEMCG_MEMORY_2048_THRES_SWAP);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_LOW, MEMCG_MEMORY_2048_THRES_LOW);
+ lowmem_memcg_set_threshold(MEMCG_MEMORY, LOWMEM_MEDIUM, MEMCG_MEMORY_2048_THRES_MEDIUM);
+ lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, MEMCG_MEMORY_2048_THRES_LEAVE);
config_parse(MEM_CONF_FILE, memory_load_2048_config, NULL);
}
- for (i = MEMNOTIFY_SWAP; i < MEMNOTIFY_MAX_LEVELS; i++)
- _I("set threshold for %d to %u", i, thresholds[i]);
+ for (i = LOWMEM_SWAP; i < LOWMEM_MAX_LEVEL; i++)
+ _I("set threshold for %d to %u", i, memcg_memory->threshold[i]);
- _I("set thres_leave to %u", memcg_class[MEMCG_MEMORY].thres_leave);
+ _I("set thres_leave to %u", memcg_memory->threshold_leave);
_I("set dynamic process threshold to %u", dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
_I("set dynamic process leave to %u", dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
}
-static int create_foreground_memcg(void)
+static int compare_victims(const struct task_info *ta, const struct task_info *tb)
{
- int i;
- char buf[LOWMEM_PATH_MAX] = {0, };
- for (i = MEMCG_FOREGROUND; i < MEMCG_MAX_GROUPS; i++) {
- sprintf(buf, "%s/%s", MEMCG_PATH, memcg_class[i].cgroup_name);
- if (mkdir(buf, 0755) && errno != EEXIST) {
- _E("mkdir %s failed, errno %d", buf, errno);
+ /*
+ * Firstly, sort by oom_score_adj
+ * Secondly, sort by task size
+ */
+ assert(ta != NULL);
+ assert(tb != NULL);
+
+ if (ta->oom_score_adj != tb->oom_score_adj)
+ return (tb->oom_score_adj - ta->oom_score_adj);
+
+ return ((int)(tb->size) - (int)(ta->size));
+}
+
+static int init_memcg_params(void)
+{
+ int idx = 0;
+ char buf[MAX_PATH_LENGTH];
+ memcg = (struct memcg_t **)malloc(sizeof(struct memcg_t *) *
+ MEMCG_MAX);
+ if (!memcg)
+ return RESOURCED_ERROR_FAIL;
+
+ for (idx = 0; idx < MEMCG_MAX; idx++) {
+ struct memcg_info_t *mi = NULL;
+ memcg[idx] = (struct memcg_t *)malloc(sizeof(struct memcg_t));
+ if (!memcg[idx]) {
+ int i;
+ for (i = 0; i < idx - 1; i++)
+ free(memcg[i]);
+ free(memcg);
+ return RESOURCED_ERROR_FAIL;
+ }
+ memcg_init(memcg[idx]);
+ if (memcg_name[idx])
+ snprintf(buf, MAX_PATH_LENGTH, "%s/%s/", LOWMEM_DEFAULT_CGROUP,
+ memcg_name[idx]);
+ else
+ snprintf(buf, MAX_PATH_LENGTH, "%s/", LOWMEM_DEFAULT_CGROUP);
+ mi = (struct memcg_info_t *)malloc(sizeof(struct memcg_info_t));
+ if (!mi) {
+ int i;
+ for (i = 0; i < idx; i++)
+ free(memcg[i]);
+ free(memcg);
return RESOURCED_ERROR_FAIL;
}
- _I("%s is successfuly created", buf);
+ memcg_info_init(mi, buf);
+ memcg[idx]->info = mi;
+ _I("init memory cgroup for %s", buf);
+ if (idx == MEMCG_MEMORY)
+ memcg_memory = memcg[idx]->info;
}
return RESOURCED_ERROR_NONE;
}
-static int init_memcg(void)
+static int write_params_memcg_info(struct memcg_info_t *mi,
+ int write_limit)
{
- unsigned int i, limit;
- _D("Total : %lu", totalram);
+ unsigned int limit = mi->limit;
+ const char *name = mi->name;
int ret = RESOURCED_ERROR_NONE;
+ _I("write memcg param for %s", name);
+ /* enable cgroup move */
+ ret = cgroup_write_node(name,
+ MEMCG_MOVE_CHARGE_PATH, 3);
+ if (ret)
+ return ret;
- for (i = 0; i < MEMCG_MAX_GROUPS; i++) {
- /* enable cgroup move */
- ret = write_cgroup_node(memcg_class[i].cgroup_name,
- MEMCG_MOVE_CHARGE_PATH, 3);
- if (ret)
- return ret;
+ /*
+ * for memcg with LOWMEM_NO_LIMIT or write_limit is not set,
+ * do not set limit for cgroup limit.
+ */
+ if (mi->limit_ratio == LOWMEM_NO_LIMIT ||
+ !write_limit)
+ return ret;
- /* for memcg with NO_LIMIT, do not set limit for cgroup limit */
- if (memcg_class[i].limit_ratio == NO_LIMIT)
- continue;
+ /* disable memcg OOM-killer */
+ ret = cgroup_write_node(name,
+ MEMCG_OOM_CONTROL_PATH, 1);
+ if (ret)
+ return ret;
- /* disable memcg OOM-killer */
- ret = write_cgroup_node(memcg_class[i].cgroup_name,
- MEMCG_OOM_CONTROL_PATH, 1);
- if (ret)
- return ret;
-
- /* write limit_in_bytes */
- limit = (unsigned int)(memcg_class[i].limit_ratio*(float)totalram);
- if (limit > memcg_class[i].min_limit)
- limit = memcg_class[i].min_limit;
- ret = write_cgroup_node(memcg_class[i].cgroup_name,
- MEMCG_LIMIT_PATH, limit);
- if (ret)
- return ret;
- else
- _I("set %s's limit to %u", memcg_class[i].cgroup_name, limit);
+ /* write limit_in_bytes */
+ ret = cgroup_write_node(name,
+ MEMCG_LIMIT_PATH, limit);
+ _I("set %s's limit to %u", name, limit);
+ return ret;
+}
- if (BtoMB(totalram) < MEM_SIZE_512 &&
- (i >= MEMCG_FOREGROUND && i < MEMCG_BACKGROUND)) {
- memcg_class[i].thres_leave = limit * MEMCG_FOREGROUND_LEAVE_RATIO;
- _I("set foreground%d leave %u for limit %u",
- i, memcg_class[i].thres_leave, limit);
+static int write_memcg_params(void)
+{
+ unsigned int i;
+ _D("Total : %lu", totalram);
+ int ret = RESOURCED_ERROR_NONE;
+ GSList *iter = NULL;
+
+ for (i = 0; i < MEMCG_MAX; i++) {
+ struct memcg_info_t *mi = memcg[i]->info;
+ int write_limit = !memcg[i]->use_hierarchy;
+ GSList *list = memcg[i]->cgroups;
+ write_params_memcg_info(mi, write_limit);
+ /* write limit to the node for sub cgroups */
+ write_limit = 1;
+ /* write node for sub cgroups */
+ gslist_for_each_item(iter, list) {
+ struct memcg_info_t *mi =
+ (struct memcg_info_t *)(iter->data);
+ write_params_memcg_info(mi, write_limit);
}
-
- /* set threshold and oomleave for each memcg */
- memcg_class[i].thres_low =
- (unsigned int)(limit * MEMCG_LOW_RATIO);
- memcg_class[i].thres_medium =
- (unsigned int)(limit * MEMCG_MEDIUM_RATIO);
- memcg_class[i].oomleave =
- limit - (memcg_class[i].thres_leave << 20);
}
return ret;
@@ -1737,89 +1745,104 @@ static void lowmem_check(void)
available = get_available();
_D("available = %u", available);
- if(cur_mem_state != MEMNOTIFY_SWAP &&
- (available <= thresholds[MEMNOTIFY_SWAP] &&
- available > thresholds[MEMNOTIFY_LOW])) {
+ if(cur_mem_state != LOWMEM_SWAP &&
+ (available <= memcg_memory->threshold[LOWMEM_SWAP] &&
+ available > memcg_memory->threshold[LOWMEM_LOW])) {
swap_act();
}
}
-static int find_foreground_cgroup(struct proc_process_info_t *process_info) {
- int fg, min_fg = -1;
+static struct memcg_info_t *find_foreground_cgroup(struct proc_process_info_t *ppi) {
+ unsigned int usage;
unsigned int min_usage = UINT_MAX;
+ struct memcg_info_t *min_mi = NULL, *mi;
+ GSList *iter = NULL;
/*
* if this process group is already in one of the foreground cgroup,
* put all of the process in this group into the same cgroup.
*/
- if (process_info && process_info->memcg_idx >= MEMCG_FOREGROUND &&
- process_info->memcg_idx < MEMCG_FOREGROUND + NUM_FOREGROUND)
- return process_info->memcg_idx;
+ if (ppi &&
+ ppi->memcg_idx == MEMCG_FOREGROUND) {
+ _D("%s is already in foreground", ppi->appid);
+ return ppi->memcg_info;
+ }
/*
* if any of the process in this group is not in foreground,
* find foreground cgroup with minimum usage
*/
- for (fg = MEMCG_FOREGROUND; fg < MEMCG_BACKGROUND; fg++) {
- unsigned int usage;
- usage = get_mem_usage(fg);
-
- /* select foreground memcg with no task first*/
- if (usage == 0)
- return fg;
-
- /* select forground memcg with minimum usage */
- if (usage > 0 && min_usage > usage) {
- min_usage = usage;
- min_fg = fg;
+ if (memcg[MEMCG_FOREGROUND]->use_hierarchy) {
+ gslist_for_each_item(iter,
+ memcg[MEMCG_FOREGROUND]->cgroups) {
+ mi = (struct memcg_info_t *)(iter->data);
+ const char *name = mi->name;
+
+ usage = get_cgroup_mem_usage(name);
+ /* select foreground memcg with no task first */
+ if (usage == 0) {
+ _D("%s' usage is 0, selected", name);
+ return mi;
+ }
+
+ /* select forground memcg with minimum usage */
+ if (usage > 0 && min_usage > usage) {
+ min_usage = usage;
+ min_mi = mi;
+ }
}
- }
+ _D("%s is selected at min usage = %u",
+ min_mi->name, min_usage);
- if (min_fg < 0)
- return RESOURCED_ERROR_FAIL;
+ } else {
+ return memcg[MEMCG_FOREGROUND]->info;
+ }
- return min_fg;
+ return min_mi;
}
static void lowmem_move_memcgroup(int pid, int oom_score_adj)
{
- char buf[LOWMEM_PATH_MAX] = {0,};
+ char buf[BUF_MAX] = {0,};
FILE *f;
int size, background = 0;
- unsigned long swap_args[1] = {0,};
- struct proc_process_info_t *process_info =
+ const char *name;
+ struct proc_process_info_t *ppi =
find_process_info(NULL, pid, NULL);
if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED) {
- sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
- proc_set_process_info_memcg(process_info, MEMCG_BACKGROUND);
+ struct memcg_info_t *mi =
+ memcg[MEMCG_BACKGROUND]->info;
+ name = mi->name;
+ sprintf(buf, "%scgroup.procs", name);
+ proc_set_process_info_memcg(ppi,
+ MEMCG_BACKGROUND, mi);
background = 1;
} else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED &&
- oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
- int ret = find_foreground_cgroup(process_info);
- if (ret == RESOURCED_ERROR_FAIL) {
- _E("cannot find foreground cgroup");
- return;
- }
- sprintf(buf, "%s/memory/foreground%d/cgroup.procs", MEMCG_PATH, ret);
- proc_set_process_info_memcg(process_info, ret);
+ oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
+ struct memcg_info_t *mi =
+ find_foreground_cgroup(ppi);
+ name = mi->name;
+ sprintf(buf, "%scgroup.procs", name);
+ proc_set_process_info_memcg(ppi,
+ MEMCG_FOREGROUND, mi);
} else
return;
- swap_args[0] = (unsigned long)pid;
- if (!swap_status(SWAP_CHECK_PID, swap_args) || !background) {
+ if (!swap_check_swap_pid(pid) || !background) {
_D("buf : %s, pid : %d, score : %d", buf, pid, oom_score_adj);
f = fopen(buf, "w");
if (!f) {
- _E("%s open failed", buf);
- return;
+ _E("%s open failed", buf);
+ return;
}
size = sprintf(buf, "%d", pid);
if (fwrite(buf, size, 1, f) != 1)
- _E("fwrite cgroup tasks : %d\n", pid);
+ _E("fwrite cgroup tasks : %d\n", pid);
fclose(f);
}
+
if (background) {
lowmem_check();
lowmem_swap_memory();
@@ -1829,17 +1852,17 @@ static void lowmem_move_memcgroup(int pid, int oom_score_adj)
static void lowmem_cgroup_foregrd_manage(int currentpid)
{
GSList *iter;
- struct proc_process_info_t *process_info =
+ struct proc_process_info_t *ppi =
find_process_info(NULL, currentpid, NULL);
- if (!process_info)
+ if (!ppi)
return;
- gslist_for_each_item(iter, process_info->pids) {
- struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
+ gslist_for_each_item(iter, ppi->pids) {
+ struct pid_info_t *pi = (struct pid_info_t *)(iter->data);
- if (pid_info->type == RESOURCED_APP_TYPE_GROUP)
- lowmem_move_memcgroup(pid_info->pid, OOMADJ_FOREGRD_UNLOCKED);
+ if (pi->type == PROC_TYPE_GROUP)
+ lowmem_move_memcgroup(pi->pid, OOMADJ_FOREGRD_UNLOCKED);
}
}
@@ -1863,17 +1886,34 @@ static int oom_thread_create(void)
return ret;
}
-static int lowmem_app_launch_cb(void *data)
+static int create_memcgs(void)
{
- struct proc_status *p_data = (struct proc_status*)data;
- struct proc_process_info_t *process_info;
- int ret = 0;
- ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
- "Please provide valid argument!");
- process_info = (struct proc_process_info_t *)p_data->processinfo;
+ int i = 0;
+ int ret = RESOURCED_ERROR_NONE;
+ GSList *iter = NULL;
+ struct memcg_info_t *mi;
+ char *name;
+
+ /* skip for memory cgroup */
+ for (i = 0; i < MEMCG_MAX; i++) {
+ if (!memcg_name[i])
+ continue;
+ mi = memcg[i]->info;
+ name = mi->name;
+ ret = make_cgroup_subdir(NULL, name, NULL);
+ if (!memcg[i]->use_hierarchy)
+ continue;
+ _D("create memory cgroup for %s, ret = %d", name, ret);
+ /* create sub cgroups */
+ gslist_for_each_item(iter, memcg[i]->cgroups) {
+ mi = (struct memcg_info_t *)
+ iter->data;
+ name = mi->name;
+ ret = make_cgroup_subdir(NULL, name, NULL);
+ _D("make cgroup subdir for %s, ret = %d", name, ret);
+ }
+ }
- if (process_info && !(process_info->type & PROC_LARGE_HEAP))
- lowmem_dynamic_process_killer(DYNAMIC_KILL_LUNCH);
return ret;
}
@@ -1882,29 +1922,21 @@ int lowmem_init(void)
{
int ret = RESOURCED_ERROR_NONE;
- ret = create_foreground_memcg();
-
- if (ret) {
- _E("create foreground memcgs failed");
- return ret;
- }
get_total_memory();
- init_thresholds();
+
+ init_memcg_params();
+ setup_memcg_params();
config_parse(MEM_CONF_FILE, load_mem_config, NULL);
+ create_memcgs();
+ write_memcg_params();
+
ret = oom_thread_create();
if (ret) {
_E("oom thread create failed\n");
return ret;
}
- /* set default memcg value */
- ret = init_memcg();
- if (ret) {
- _E("memory cgroup init failed");
- return ret;
- }
-
/* register threshold and event fd */
ret = setup_eventfd();
if (ret) {
@@ -1913,11 +1945,21 @@ int lowmem_init(void)
}
lowmem_dbus_init();
- register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
return ret;
}
+static int lowmem_exit(void)
+{
+ int i;
+ for (i = 0; i < MEMCG_MAX; i++) {
+ g_slist_free_full(memcg[i]->cgroups, free);
+ free(memcg[i]->info);
+ free(memcg[i]);
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
static int resourced_memory_control(void *data)
{
int ret = RESOURCED_ERROR_NONE;
@@ -1941,14 +1983,12 @@ static int resourced_memory_control(void *data)
static int resourced_memory_init(void *data)
{
lowmem_ops = &memory_modules_ops;
-
return lowmem_init();
}
static int resourced_memory_finalize(void *data)
{
- unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
- return RESOURCED_ERROR_NONE;
+ return lowmem_exit();
}
int lowmem_control(enum lowmem_control_type type, unsigned long *args)
diff --git a/src/memps/CMakeLists.txt b/src/memps/CMakeLists.txt
index 80bfc202..07cbe250 100644
--- a/src/memps/CMakeLists.txt
+++ b/src/memps/CMakeLists.txt
@@ -1,7 +1,7 @@
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror")
-SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -pie")
IF("${ARCH}" STREQUAL "arm")
ADD_DEFINITIONS("-DTARGET")
diff --git a/src/memps/memps.c b/src/memps/memps.c
index bc7b7527..ae7edecd 100644
--- a/src/memps/memps.c
+++ b/src/memps/memps.c
@@ -1053,7 +1053,11 @@ void check_kernel_version(void)
char str[3];
int sub_version;
pch = strstr(buf.release, ".");
+ if (!pch)
+ return;
+
strncpy(str, pch+1, 2);
+ str[2] = '\0';
sub_version = atoi(str);
if (sub_version >= 10)
@@ -1065,7 +1069,7 @@ void check_kernel_version(void)
ignore_smaps_field = 7; /* Referenced, Anonymous, AnonHugePages,
Swap, KernelPageSize, MMUPageSize,
Locked */
- } else {
+ } else {
ignore_smaps_field = 4; /* Referenced, Swap, KernelPageSize,
MMUPageSize */
}
diff --git a/src/network/500.resourced-datausage.patch.sh b/src/network/500.resourced-datausage.patch.sh
new file mode 100644
index 00000000..43f25ec9
--- /dev/null
+++ b/src/network/500.resourced-datausage.patch.sh
@@ -0,0 +1,19 @@
+sqlite3 /opt/usr/dbspace/.resourced-datausage.db "
+PRAGMA journal_mode=PERSIST;
+DROP TABLE IF EXISTS fota;
+ALTER TABLE restrictions RENAME to fota;
+CREATE TABLE IF NOT EXISTS restrictions (
+binpath TEXT,
+rcv_limit BIGINT,
+send_limit BIGINT,
+iftype INT,
+rst_state INT,
+quota_id INT,
+roaming INT,
+reserved TEXT,
+ifname TEXT,
+PRIMARY KEY (binpath, iftype, ifname, quota_id)
+);
+INSERT INTO restrictions select * from fota;
+DROP TABLE IF EXISTS fota;
+"
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index c02da8d8..792223db 100755
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -1,13 +1,27 @@
SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(PROJECT ${RESOURCED})
+PROJECT(${PROJECT})
+
IF("${NETWORK_MODULE}" STREQUAL "OFF")
- MESSAGE("DataUsage is disbaled")
+ INCLUDE_DIRECTORIES(${INCLUDE_PUBLIC_DIR}
+ ${INCLUDE_COMMON_DIR})
+ SET(SOURCES ${NETWORK_SOURCE_DIR}/join-dummy.c)
+ ADD_LIBRARY(${PROJECT} SHARED ${SOURCES})
+ TARGET_LINK_LIBRARIES(${PROJECT} ${shared_pkgs_LDFLAGS})
+
+ SET_TARGET_PROPERTIES(${PROJECT}
+ PROPERTIES
+ VERSION ${FULLVER}
+ SOVERSION ${MAJORVER}
+ CLEAN_DIRECT_OUTPUT 1
+ )
+
+ INSTALL(TARGETS ${PROJECT} DESTINATION ${LIB_INSTALL_DIR})
+
RETURN()
ENDIF()
-SET(PROJECT ${RESOURCED})
-PROJECT(${PROJECT})
-
INCLUDE_DIRECTORIES(${INCLUDE_PUBLIC_DIR}
${NETWORK_SOURCE_DIR}/include
${RESOURCED_INCLUDEDIR}
@@ -19,13 +33,10 @@ SET (REQUIRES_LIST dlog
vconf
ecore
edbus
+ openssl
+ tapi
)
-IF("${TETHERING_FEATURE}" STREQUAL "ON")
- SET(REQUIRES_LIST ${REQUIRES_LIST}
- capi-network-connection)
-ENDIF()
-
INCLUDE(FindPkgConfig)
pkg_check_modules(pkgs_${NETWORK} REQUIRED ${REQUIRES_LIST})
@@ -62,12 +73,6 @@ SET(storage_SOURCES
${NETWORK_SOURCE_DIR}/datausage-quota-processing.c #storage uses it
${NETWORK_SOURCE_DIR}/storage.c)
-SET(protocol-info_HEADERS
- ${NETWORK_SOURCE_DIR}/include/protocol-info.h)
-
-SET(protocol-info_SOURCES
- ${NETWORK_SOURCE_DIR}/protocol-info.c)
-
SET(quota_HEADERS
${NETWORK_SOURCE_DIR}/include/datausage-quota-processing.h)
@@ -76,9 +81,6 @@ SET(quota_SOURCES
${NETWORK_SOURCE_DIR}/datausage-quota.c
)
-SET(app-stat_HEADERS
- ${INCLUDE_COMMON_DIR}/app-stat.h)
-
SET(app-stat_SOURCES
${NETWORK_SOURCE_DIR}/app-stat.c)
@@ -87,33 +89,31 @@ SET(net-iface_HEADERS
SET(net-iface_SOURCES
${NETWORK_SOURCE_DIR}/iface.c
+ ${COMMON_SOURCE_DIR}/config-parser.c
)
-SET(roaming_HEADERS
- ${NETWORK_SOURCE_DIR}/include/roaming.h)
-
-SET(roaming_SOURCES
- ${NETWORK_SOURCE_DIR}/dummy_roaming.c)
+SET(telephony_HEADERS
+ ${NETWORK_SOURCE_DIR}/include/telephony.h)
-ADD_LIBRARY(protocol-info STATIC
- ${protocol-info_SOURCES} ${protocol-info_HEADERS})
+SET(telephony_SOURCES
+ ${NETWORK_SOURCE_DIR}/telephony.c)
ADD_LIBRARY(storage STATIC
${storage_SOURCES} ${storage_HEADERS}
${quota_SOURCES} ${quota_HEADERS}
)
-TARGET_LINK_LIBRARIES(storage protocol-info ${pkgs_${NETWORK}_LDFLAGS})
+TARGET_LINK_LIBRARIES(storage ${pkgs_${NETWORK}_LDFLAGS})
ADD_LIBRARY(app-stat STATIC
- ${app-stat_SOURCES} ${app-stat_HEADERS})
+ ${app-stat_SOURCES})
TARGET_LINK_LIBRARIES(app-stat net-cls)
ADD_LIBRARY(net-iface STATIC
${net-iface_SOURCES})
-ADD_LIBRARY(roaming STATIC
- ${roaming_SOURCES})
-TARGET_LINK_LIBRARIES(roaming ${pkgs_${NETWORK}_LDFLAGS})
+ADD_LIBRARY(telephony STATIC
+ ${telephony_SOURCES})
+TARGET_LINK_LIBRARIES(telephony ${pkgs_${NETWORK}_LDFLAGS})
SET(net-cls_HEADERS
${NETWORK_SOURCE_DIR}/include/net-cls-cgroup.h)
@@ -175,17 +175,13 @@ ENDFOREACH(flag)
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC")
-INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
- ${NETWORK_SOURCE_DIR}/include
- ${RESOURCED_SOURCE_DIR})
-
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
ADD_LIBRARY(${PROJECT} SHARED
${${PROJECT}_HEADERS}
${${PROJECT}_SOURCES})
-TARGET_LINK_LIBRARIES(${PROJECT} roaming settings net-cls
+TARGET_LINK_LIBRARIES(${PROJECT} telephony settings net-cls
${shared_pkgs_LDFLAGS})
SET_TARGET_PROPERTIES(${PROJECT}
@@ -199,30 +195,12 @@ ADD_EXECUTABLE(datausagetool ${UTILS_SOURCE_DIR}/datausage-tool.c)
TARGET_LINK_LIBRARIES(datausagetool
${PROJECT}
${COMMON_SOURCE_DIR}/config-parser.c
- net-iface)
+ # ${NETWORK_SOURCE_DIR}/app-stat.c
+ net-iface
+ )
INSTALL(TARGETS datausagetool
DESTINATION /usr/bin)
INSTALL(TARGETS ${PROJECT} DESTINATION ${LIB_INSTALL_DIR})
INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/data_usage.h DESTINATION include/system)
#### lib-resourced ####
-
-#### rd-network ####
-SET(SOURCES
- ${NETWORK_SOURCE_DIR}/network-dummy.c)
-
-ADD_LIBRARY(${NETWORK} SHARED ${SOURCES})
-ADD_DEPENDENCIES(${NETWORK} ${PROJECT})
-TARGET_LINK_LIBRARIES(${NETWORK} ${${NETWORK}_LDFLAGS} -L${LIBRARY_OUTPUT_PATH} -l${PROJECT})
-
-SET_TARGET_PROPERTIES(${NETWORK}
- PROPERTIES
- VERSION ${FULLVER}
- SOVERSION ${MAJORVER}
- CLEAN_DIRECT_OUTPUT 1
-)
-
-INSTALL(TARGETS ${NETWORK} DESTINATION ${LIB_INSTALL_DIR})
-INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/rd-network.h DESTINATION include/system)
-
-#### rd-network ####
diff --git a/src/network/app-stat.c b/src/network/app-stat.c
index 35bd8a84..9c35d950 100644
--- a/src/network/app-stat.c
+++ b/src/network/app-stat.c
@@ -24,16 +24,24 @@
* @desc application statistics entity helper functions
*/
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "app-stat.h"
+#include "counter.h"
+#include "datausage-common.h"
#include "net-cls-cgroup.h"
#include "iface.h"
#include "macro.h"
-#include "roaming.h"
+#include "telephony.h"
#include "trace.h"
+#ifdef CONFIG_DATAUSAGE_NFACCT
+#include "nfacct-rule.h"
+#else
+#include "genl.h"
+#endif
static void free_app(gpointer data)
{
@@ -52,22 +60,23 @@ static gint compare_classid(gconstpointer a, gconstpointer b,
{
const struct classid_iftype_key *a_key = (struct classid_iftype_key*)a;
const struct classid_iftype_key *b_key = (struct classid_iftype_key*)b;
- gint ret = 0;
+ gint ret = a_key->classid - b_key->classid;
- ret = a_key->classid - b_key->classid;
- if (!ret)
+ if (ret)
return ret;
ret = a_key->iftype - b_key->iftype;
- if (!ret)
+ if (ret)
return ret;
- return strcmp(a_key->ifname, b_key->ifname);
-}
+ ret = (a_key->ifname && b_key->ifname) ?
+ strcmp(a_key->ifname, b_key->ifname) : 0;
-static void free_stat(gpointer data)
-{
- free(data);
+ if (ret)
+ return ret;
+
+ return (a_key->imsi && b_key->imsi) ?
+ strcmp(a_key->imsi, b_key->imsi) : 0;
}
struct application_stat_tree *create_app_stat_tree(void)
@@ -84,7 +93,7 @@ struct application_stat_tree *create_app_stat_tree(void)
app_stat_tree->tree =
(GTree *)g_tree_new_full(compare_classid,
- NULL, free_stat,
+ NULL, free,
free_app);
app_stat_tree->last_touch_time = time(0);
ret = pthread_rwlock_init(&app_stat_tree->guard, NULL);
@@ -111,16 +120,6 @@ void nulify_app_stat_tree(struct application_stat_tree **app_stat_tree)
*app_stat_tree = NULL;
}
-traffic_stat_tree *create_traffic_stat_tree(void)
-{
- return g_tree_new_full(compare_classid, NULL, NULL, free_stat);
-}
-
-void free_traffic_stat_tree(traffic_stat_tree *tree)
-{
- g_tree_destroy((GTree *) tree);
-}
-
static gboolean set_app_id(gpointer key, gpointer value,
void __attribute__((__unused__)) *data)
{
@@ -139,81 +138,165 @@ static inline void identify_application(
g_tree_foreach(app_stat_tree->tree, (GTraverseFunc)set_app_id, NULL);
}
-static gboolean fill_incomming(gpointer key,
- gpointer value, gpointer data)
+#ifdef CONFIG_DATAUSAGE_NFACCT
+
+static void fill_nfacct_counter(struct nfacct_rule *counter, uint64_t bytes)
{
+ struct classid_iftype_key *key;
+ struct classid_iftype_key search_key = {0};
+ struct counter_arg *carg = counter->carg;
struct application_stat_tree *app_tree =
- (struct application_stat_tree *)data;
- struct traffic_stat *in_event = (struct traffic_stat *)value;
-
+ (struct application_stat_tree *)carg->result;
struct application_stat *app_stat = NULL;
- if (!is_allowed_ifindex(in_event->ifindex))
- return FALSE;
+
+ search_key.classid = counter->classid;
+ search_key.iftype = counter->iftype;
+ STRING_SAVE_COPY(search_key.ifname, counter->ifname);
+ search_key.imsi = counter->iftype == RESOURCED_IFACE_DATACALL ?
+ get_current_modem_imsi() : ""; /* we'll not free it */
app_stat = (struct application_stat *)
- g_tree_lookup((GTree *)app_tree->tree, key);
- if (app_stat)
- app_stat->rcv_count += in_event->bytes;
- else {
+ g_tree_lookup((GTree *)app_tree->tree, &search_key);
+
+ if (!app_stat) {
+ key = g_new(struct classid_iftype_key, 1);
+
+ if (!key) {
+ _D("g_new alloc error\n");
+ return;
+ }
+ memcpy(key, &search_key, sizeof(struct classid_iftype_key));
+ STRING_SAVE_COPY(key->ifname, search_key.ifname);
+
app_stat = g_new(struct application_stat, 1);
+ if (!app_stat) {
+ _D("g_new alloc error\n");
+ g_free((gpointer)key);
+ return;
+ }
memset(app_stat, 0, sizeof(struct application_stat));
- app_stat->rcv_count = in_event->bytes;
- g_tree_insert((GTree *)app_tree->tree, key, app_stat);
+ g_tree_insert((GTree *)app_tree->tree, (gpointer)key, (gpointer)app_stat);
+ _D("new app stat for classid %u\n", counter->classid);
+ } else {
+ _D("app stat for classid %d found in tree", search_key.classid);
+ _D("app stats app id %s", app_stat->application_id);
+ _D("counter intend %d", counter->intend);
}
- app_stat->delta_rcv += in_event->bytes;
- /*only for debug purpose*/
- if (!app_stat->ifindex)
- app_stat->ifindex = in_event->ifindex;
+ if (counter->iotype == NFACCT_COUNTER_IN) {
+ app_stat->delta_rcv += bytes; /* += because we could update
+ counters several times before
+ flush it */
+ app_stat->rcv_count += bytes; /* for different update/flush interval
+ in quota processing,
+ quota nulifies it and flush operation
+ as well, so 2 counters */
+ } else if (counter->iotype == NFACCT_COUNTER_OUT) {
+ app_stat->delta_rcv += bytes;
+ app_stat->rcv_count += bytes;
+ }
- app_stat->is_roaming = get_roaming();
- return FALSE;
+ app_stat->is_roaming = get_current_roaming();
+ if (!app_stat->application_id)
+ app_stat->application_id = get_app_id_by_classid(counter->classid, false);
+ app_stat->ground = get_app_ground(counter);
}
-static gboolean fill_outgoing(gpointer key,
- gpointer value, gpointer data)
+static void fill_nfacct_restriction(struct nfacct_rule *counter, uint64_t bytes)
{
- struct application_stat_tree *app_tree =
- (struct application_stat_tree *)data;
- struct traffic_stat *out_event = (struct traffic_stat *)value;
-
- struct application_stat *app_stat = (struct application_stat *)
- g_tree_lookup((GTree *)app_tree->tree, key);
- if (app_stat)
- app_stat->snd_count += out_event->bytes;
- else {
- app_stat = g_new(struct application_stat, 1);
- memset(app_stat, 0, sizeof(struct application_stat));
- app_stat->snd_count = out_event->bytes;
- g_tree_insert((GTree *)app_tree->tree, key, app_stat);
+ /* update db from here ? */
+ _D("byte for restriction %" PRIu64 " ", bytes);
+ update_counter_quota_value(counter, bytes);
+}
+
+void fill_nfacct_result(char *cnt_name, uint64_t bytes,
+ struct counter_arg *carg)
+{
+ struct nfacct_rule counter = {
+ .carg = carg,
+ .name = {0},
+ .ifname = {0},
+ 0, };
+
+ _D("cnt_name %s", cnt_name);
+
+ if (!recreate_counter_by_name(cnt_name, &counter)) {
+ _E("Can't parse counter name %s", cnt_name);
+ return;
}
- app_stat->delta_snd += out_event->bytes;
- if (!app_stat->ifindex)
- app_stat->ifindex = out_event->ifindex;
+ _D("classid %u, iftype %u, iotype %d, intend %d, ifname %s, bytes %lu",
+ counter.classid, counter.iftype, counter.iotype, counter.intend, counter.ifname, bytes);
- if (!app_stat->is_roaming)
- app_stat->is_roaming = get_roaming();
- return FALSE;
+ if (counter.iotype == NFACCT_COUNTER_UNKNOWN) {
+ _D("Counter type is not supported!");
+ return;
+ }
+ if (counter.intend == NFACCT_COUNTER ||
+ counter.intend == NFACCT_TETH_COUNTER) {
+ return fill_nfacct_counter(&counter, bytes);
+ } else if (counter.intend == NFACCT_BLOCK)
+ return fill_nfacct_restriction(&counter, bytes);
}
+#else
+API void fill_app_stat_result(int ifindex, int classid, uint64_t bytes, int iotype,
+ struct counter_arg *carg)
+{
+ struct classid_iftype_key *key;
+ struct classid_iftype_key search_key = {0};
+ char *ifname;
+ struct application_stat_tree *app_tree =
+ (struct application_stat_tree *)carg->result;
+ struct application_stat *app_stat = NULL;
-static void fill_result(traffic_stat_tree *tree_in,
- traffic_stat_tree *tree_out,
- struct application_stat_tree *result)
-{
+ search_key.classid = classid;
+ search_key.iftype = get_iftype(ifindex);
+ ifname = get_iftype_name(search_key.iftype);
+ STRING_SAVE_COPY(search_key.ifname, ifname);
+ search_key.imsi = search_key.iftype == RESOURCED_IFACE_DATACALL ?
+ get_current_modem_imsi() : ""; /* we'll not free it */
- g_tree_foreach(tree_in, (GTraverseFunc)fill_incomming, result);
- g_tree_foreach(tree_out, (GTraverseFunc)fill_outgoing, result);
-}
+ app_stat = (struct application_stat *)
+ g_tree_lookup((GTree *)app_tree->tree, &search_key);
-resourced_ret_c prepare_application_stat(traffic_stat_tree *tree_in,
- traffic_stat_tree *tree_out,
- struct application_stat_tree *result,
- volatile struct daemon_opts *opts)
-{
- fill_result(tree_in, tree_out, result);
- identify_application(result);
+ if (!app_stat) {
+ key = g_new(struct classid_iftype_key, 1);
+
+ if (!key) {
+ _D("g_new alloc error\n");
+ return;
+ }
+ memcpy(key, &search_key, sizeof(struct classid_iftype_key));
+ STRING_SAVE_COPY(key->ifname, search_key.ifname);
+
+ app_stat = g_new(struct application_stat, 1);
+ if (!app_stat) {
+ _D("g_new alloc error\n");
+ g_free((gpointer)key);
+ return;
+ }
+ memset(app_stat, 0, sizeof(struct application_stat));
+ g_tree_insert((GTree *)app_tree->tree, (gpointer)key, (gpointer)app_stat);
+ _D("new app stat for classid %u\n", classid);
+ }
+
+ if (iotype == TRAF_STAT_C_GET_CONN_IN) {
+ app_stat->delta_rcv += bytes; /* += because we could update
+ counters several times before
+ flush it */
+ app_stat->rcv_count += bytes; /* for different update/flush interval
+ in quota processing,
+ quota nulifies it and flush operation
+ as well, so 2 counters */
+ } else if (iotype == TRAF_STAT_C_GET_PID_OUT) {
+ app_stat->delta_snd += bytes;
+ app_stat->snd_count += bytes;
+ }
+
+ app_stat->is_roaming = get_current_roaming();
+ if (!app_stat->application_id)
+ app_stat->application_id = get_app_id_by_classid(classid, false);
- return RESOURCED_ERROR_NONE;
}
+#endif /* CONFIG_DATAUSAGE_NFACCT */
diff --git a/src/network/counter-process.c b/src/network/counter-process.c
index f8abd53a..20a03fd4 100644
--- a/src/network/counter-process.c
+++ b/src/network/counter-process.c
@@ -43,7 +43,7 @@
#include "module-data.h"
#include "notification.h"
#include "resourced.h"
-#include "roaming.h"
+#include "telephony.h"
#include "storage.h"
#include "trace.h"
#include "transmission.h"
@@ -62,10 +62,10 @@ static char *null_str = "(null)";
#define INSERT_QUERY "REPLACE INTO quotas " \
"(binpath, sent_quota, rcv_quota, " \
"snd_warning_threshold, rcv_warning_threshold, time_period, " \
- "start_time, iftype, roaming) " \
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"
+ "start_time, iftype, roaming, imsi, ground) " \
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
#define REMOVE_QUOTA "DELETE FROM quotas WHERE binpath=? AND iftype=? " \
- " AND roaming=?"
+ " AND roaming=? AND imsi=? AND ground=?"
#define QUOTA_CEILING_VALUE 10737418220
@@ -103,7 +103,13 @@ static bool check_net_blocked(sig_atomic_t state)
#ifdef CONFIG_DATAUSAGE_NFACCT
static Eina_Bool send_counter_request(struct counter_arg *carg)
{
- return nfacct_send_get(carg) == RESOURCED_ERROR_NONE ?
+ resourced_ret_c ret;
+ if (CHECK_BIT(carg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE))
+ ret = nfacct_send_get_all(carg);
+ else
+ ret = nfacct_send_get_counters(carg, NULL);
+
+ return ret == RESOURCED_ERROR_NONE ?
ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL;
}
@@ -129,6 +135,10 @@ static void populate_counters(char *cnt_name,
return;
}
+ if (counter.intend == NFACCT_TETH_COUNTER) {
+ _D("no need to populate already created counters");
+ return;
+ }
counter.carg = carg;
strcpy(counter.name, cnt_name);
jump = get_counter_jump(counter.intend);
@@ -138,55 +148,17 @@ static void populate_counters(char *cnt_name,
produce_net_rule(&counter, 0, 0,
NFACCT_ACTION_APPEND, jump, counter.iotype);
-
- keep_counter(&counter);
}
-static void populate_traf_stat_list(char *cnt_name, uint64_t bytes,
- struct counter_arg *carg)
+static void finalize_response(const char *cnt_name, struct counter_arg *carg)
{
- struct traffic_stat *to_insert;
- struct classid_iftype_key *key;
- struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
- traffic_stat_tree *tree = NULL;
+ struct nfacct_rule counter = { .carg = carg, 0 };
+#ifdef DEBUG_ENABLED
_D("cnt_name %s", cnt_name);
-
- if (!recreate_counter_by_name(cnt_name, &counter)) {
- _E("Can't parse counter name %s", cnt_name);
- return;
- }
-
- _D("classid %u, iftype %u, iotype %d, intend %d, ifname %s, bytes %lu",
- counter.classid, counter.iftype, counter.iotype, counter.intend, counter.ifname, bytes);
-
- if (counter.iotype == NFACCT_COUNTER_UNKNOWN ||
- counter.intend != NFACCT_COUNTER) {
- _E("Counter type is not supported!");
- return;
- }
-
- tree = counter.iotype == NFACCT_COUNTER_IN ? carg->in_tree : carg->out_tree;
- to_insert = g_new(struct traffic_stat, 1);
- if (!to_insert) {
- _D("Can't allocate %d bytes for traffic_stat\n", sizeof(struct traffic_stat));
- return;
- }
-
- key = g_new(struct classid_iftype_key, 1);
-
- if (!key) {
- _D("Can't allocate %d bytes for classid_iftype_key\n", sizeof(struct classid_iftype_key));
- g_free((gpointer)to_insert);
- return;
- }
-
- to_insert->bytes = bytes;
- /*to_insert->ifindex = cur->ifindex;*/
- key->classid = counter.classid;
- key->iftype = counter.iftype;
- STRING_SAVE_COPY(key->ifname, counter.ifname);
- g_tree_insert((GTree *) tree, (gpointer)key, to_insert);
+#endif
+ recreate_counter_by_name((char *)cnt_name, &counter);
+ finalize_counter(&counter);
}
static int fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
@@ -203,8 +175,11 @@ static int fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
/* TODO: optimize at kernel level, kernel should not send counter
* in case of 0 bytes, it's necessary to introduce new NFACCT_*
* command */
- if (bytes)
- populate_traf_stat_list(cnt_name, bytes, carg);
+ if (bytes) {
+ ++carg->serialized_counters;
+ fill_nfacct_result(cnt_name, bytes, carg);
+ }
+ finalize_response(cnt_name, carg);
}
return 0;
@@ -240,23 +215,23 @@ static Eina_Bool send_counter_request(struct counter_arg *carg)
static Eina_Bool _counter_func_cb(void *user_data)
{
struct counter_arg *carg = (struct counter_arg *)user_data;
+ Eina_Bool cb_result = ECORE_CALLBACK_RENEW;
if (check_net_blocked(carg->opts->state)) {
ecore_timer_freeze(carg->ecore_timer);
return ECORE_CALLBACK_RENEW;
}
- if (!(carg->opts->state & RESOURCED_FORCIBLY_QUIT_STATE)) {
- /* Here we just sent command,
- * answer we receiving in another callback, send_command uses
- * return value the same as sendto
- */
+ /* Here we just sent command,
+ * answer we receiving in another callback, send_command uses
+ * return value the same as sendto */
+ cb_result = send_counter_request(carg);
- return send_counter_request(carg);
- }
+ /* In case of FORCIBLY_QUIT_STATE we just send one request and exit */
+ if (CHECK_BIT(carg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE))
+ return ECORE_CALLBACK_CANCEL;
- close(carg->sock);
- return ECORE_CALLBACK_CANCEL;
+ return cb_result;
}
static dbus_bool_t deserialize_restriction(
@@ -317,8 +292,9 @@ static DBusMessage *edbus_process_restriction(E_DBus_Object *obj,
goto out;
}
+ /* restriction is not imsi based */
dbus_ret = proc_keep_restriction(appid, NONE_QUOTA_ID, &rest,
- rst_type);
+ rst_type, false);
out:
dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &dbus_ret);
@@ -336,9 +312,10 @@ static DBusMessage *edbus_update_counters(E_DBus_Object *obj, DBusMessage *msg)
"Method is not supported");
if (m_data != NULL && m_data->carg != NULL) {
- if (!(m_data->carg->opts->state & RESOURCED_FORCIBLY_QUIT_STATE))
- m_data->carg->opts->state |=
- RESOURCED_FORCIBLY_FLUSH_STATE;
+ if (!(CHECK_BIT(m_data->carg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE))) {
+ SET_BIT(m_data->carg->opts->state, RESOURCED_FORCIBLY_FLUSH_STATE);
+ SET_BIT(m_data->carg->opts->state, RESOURCED_UPDATE_REQUESTED);
+ }
/* postpone periodic update on one minute */
reschedule_count_timer(m_data->carg, COUNTER_UPDATE_PERIOD);
@@ -349,18 +326,6 @@ static DBusMessage *edbus_update_counters(E_DBus_Object *obj, DBusMessage *msg)
return reply;
}
-struct serialization_quota {
- int time_period;
- int64_t snd_quota;
- int64_t rcv_quota;
- int snd_warning_threshold;
- int rcv_warning_threshold;
- resourced_state_t quota_type;
- resourced_iface_type iftype;
- time_t start_time;
- resourced_roaming_type roaming_type;
-};
-
static inline int _get_threshold_part(int time_period)
{
if (time_period < RESOURCED_PERIOD_DAY)
@@ -413,16 +378,42 @@ static dbus_bool_t deserialize_quota(
DBUS_TYPE_INT32, &quota->iftype,
DBUS_TYPE_INT32, &quota->start_time,
DBUS_TYPE_INT32, &quota->roaming_type,
+ DBUS_TYPE_STRING, &quota->imsi_hash,
DBUS_TYPE_INVALID);
if (ret == FALSE) {
_E("Can't deserialize set quota message ![%s:%s]\n",
err.name, err.message);
+ goto release;
}
- dbus_error_free(&err);
+ if (!quota->start_time) {
+ _E("Start time wasn't specified!\n");
+ ret = FALSE;
+ goto release;
+ }
- quota->iftype = (quota->iftype == RESOURCED_IFACE_UNKNOWN) ?
- RESOURCED_IFACE_ALL : quota->iftype;
+ if (!quota->time_period) {
+ _E("Time period wasn't specified!\n");
+ ret = FALSE;
+ goto release;
+ }
+
+ if(quota->iftype <= RESOURCED_IFACE_UNKNOWN ||
+ quota->iftype >= RESOURCED_IFACE_LAST_ELEM) {
+ _E("Unknown network interface is inacceptable!");
+ ret = FALSE;
+ goto release;
+ }
+
+ if (quota->roaming_type < RESOURCED_ROAMING_UNKNOWN ||
+ quota->roaming_type >= RESOURCED_ROAMING_LAST_ELEM ||
+ (quota->roaming_type == RESOURCED_ROAMING_UNKNOWN &&
+ quota->iftype == RESOURCED_IFACE_DATACALL))
+ {
+ _E("Bad roaming!");
+ ret = FALSE;
+ goto release;
+ }
quota->snd_warning_threshold = _evaluate_warning_threshold(
quota->snd_quota, quota->time_period,
@@ -430,13 +421,19 @@ static dbus_bool_t deserialize_quota(
quota->rcv_warning_threshold = _evaluate_warning_threshold(
quota->rcv_quota, quota->time_period,
quota->rcv_warning_threshold);
+ _D("calculated snd_warning_threshold %d", quota->snd_warning_threshold);
+ _D("calculated rcv_warning_threshold %d", quota->rcv_warning_threshold);
+
+release:
-return ret;
+ dbus_error_free(&err);
+ return ret;
}
static dbus_bool_t deserialize_remove_quota(
DBusMessage *msg, char **appid,
- resourced_iface_type *iftype, resourced_roaming_type *roaming)
+ resourced_iface_type *iftype, resourced_roaming_type *roaming,
+ char **imsi, resourced_state_t *ground)
{
DBusError err;
dbus_error_init(&err);
@@ -446,6 +443,8 @@ static dbus_bool_t deserialize_remove_quota(
DBUS_TYPE_STRING, appid,
DBUS_TYPE_INT32, iftype,
DBUS_TYPE_INT32, roaming,
+ DBUS_TYPE_STRING, imsi,
+ DBUS_TYPE_INT32, ground,
DBUS_TYPE_INVALID);
if (ret == FALSE) {
_E("Can't deserialize remove quota message! [%s:%s]\n",
@@ -504,7 +503,7 @@ static int init_datausage_quota_remove(sqlite3 *db)
if (datausage_quota_remove)
return SQLITE_OK;
- rc = sqlite3_prepare_v2(db, REMOVE_QUOTA, -1,
+ rc = sqlite3_prepare_v2(db, REMOVE_QUOTA, -1,
&datausage_quota_remove, NULL);
if (rc != SQLITE_OK) {
_E("can not prepare datausage_quota_remove");
@@ -517,7 +516,8 @@ static int init_datausage_quota_remove(sqlite3 *db)
}
static resourced_ret_c remove_quota(const char *app_id,
- resourced_iface_type iftype, resourced_roaming_type roaming)
+ resourced_iface_type iftype, resourced_roaming_type roaming,
+ char *imsi_hash, const resourced_state_t ground)
{
resourced_ret_c error_code = RESOURCED_ERROR_NONE;
libresourced_db_initialize_once();
@@ -546,19 +546,36 @@ static resourced_ret_c remove_quota(const char *app_id,
if (sqlite3_bind_int(datausage_quota_remove, 3, roaming)
!= SQLITE_OK) {
- _E("Can not bind iftype:%d for preparing statement",
+ _E("Can not bind roaming:%d for preparing statement",
roaming);
error_code = RESOURCED_ERROR_DB_FAILED;
goto out;
}
+ if (sqlite3_bind_text(datausage_quota_remove, 4, imsi_hash, -1, SQLITE_STATIC)
+ != SQLITE_OK) {
+ _E("Can not bind subscriber_id:%s for preparing statement",
+ imsi_hash);
+ error_code = RESOURCED_ERROR_DB_FAILED;
+ goto out;
+ }
+
+ if (sqlite3_bind_int(datausage_quota_remove, 5, ground)
+ != SQLITE_OK) {
+ _E("Can not bind ground:%d for preparing statement",
+ ground);
+ error_code = RESOURCED_ERROR_DB_FAILED;
+ goto out;
+ }
+
if (sqlite3_step(datausage_quota_remove) != SQLITE_DONE) {
_E("failed to remove record");
error_code = RESOURCED_ERROR_DB_FAILED;
goto out;
}
- restriction_set_status(RESTRICTION_STATE_UNSET);
+ if (!check_event_in_current_modem(imsi_hash, iftype))
+ check_and_clear_all_noti();
_SD("quota for app %s removed", app_id);
@@ -570,11 +587,25 @@ out:
static DBusMessage *edbus_remove_quota(E_DBus_Object *obj, DBusMessage *msg)
{
char *app_id = NULL;
+ char *imsi_hash = NULL;
+ int quota_id = 0;
resourced_iface_type iftype;
+ resourced_state_t ground;
resourced_ret_c ret = RESOURCED_ERROR_NONE;
resourced_roaming_type roaming;
DBusMessage *reply;
DBusMessageIter iter;
+ struct shared_modules_data *m_data = get_shared_modules_data();
+ struct counter_arg *carg;
+
+ if (!m_data || !m_data->carg) {
+ _E("Not enough local parameters: modules data %p, counter arg %p",
+ m_data, m_data->carg);
+ ret = RESOURCED_ERROR_INVALID_PARAMETER;
+ goto remove_out;
+ }
+
+ carg = m_data->carg;
if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
RESOURCED_NETWORK_REMOVE_QUOTA) == 0) {
@@ -582,14 +613,28 @@ static DBusMessage *edbus_remove_quota(E_DBus_Object *obj, DBusMessage *msg)
goto remove_out;
}
- if (deserialize_remove_quota(msg, &app_id, &iftype, &roaming)
+ if (deserialize_remove_quota(msg, &app_id, &iftype, &roaming, &imsi_hash, &ground)
== FALSE) {
ret = RESOURCED_ERROR_INVALID_PARAMETER;
goto remove_out;
}
- ret = remove_quota(app_id, iftype, roaming);
- update_quota_state(app_id, iftype, 0, 0, roaming);
+ ret = remove_quota(app_id, iftype, roaming, imsi_hash, ground);
+ if (check_quota_applied(app_id, iftype, roaming, imsi_hash, ground, &quota_id)) {
+ ret = remove_restriction_local(app_id, iftype, quota_id,
+ imsi_hash, ground);
+ if (ret == RESOURCED_ERROR_NONE)
+ _D("Quota was applied and restriction was removed successfully.");
+ else
+ _E("Can't remove rules for restrictions");
+ /* move background processes from BACKGROUND cgroup to
+ * their own cgroup */
+ foreground_apps(carg);
+ }
+
+ remove_quota_from_counting(app_id, iftype, roaming, imsi_hash);
+ clear_effective_quota(app_id, iftype, roaming, imsi_hash);
+ SET_BIT(carg->opts->state, RESOURCED_CHECK_QUOTA);
remove_out:
reply = dbus_message_new_method_return(msg);
@@ -618,7 +663,7 @@ static int init_datausage_quota_insert(sqlite3 *db)
}
static resourced_ret_c store_quota(const char *app_id,
- const struct serialization_quota *quota)
+ const struct serialization_quota *quota, int *quota_id)
{
resourced_ret_c error_code = RESOURCED_ERROR_NONE;
@@ -631,7 +676,7 @@ static resourced_ret_c store_quota(const char *app_id,
}
if (sqlite3_bind_text(datausage_quota_insert, 1, app_id, -1,
- SQLITE_STATIC) != SQLITE_OK) {
+ SQLITE_TRANSIENT) != SQLITE_OK) {
_SE("Can not bind app_id: %s for prepearing statement: %s",
app_id, sqlite3_errmsg(resourced_get_database()));
error_code = RESOURCED_ERROR_DB_FAILED;
@@ -696,8 +741,24 @@ static resourced_ret_c store_quota(const char *app_id,
if (sqlite3_bind_int(datausage_quota_insert, 9,
quota->roaming_type) != SQLITE_OK) {
- _E("Can not bind start_time: %d for preparing statement",
- quota->start_time);
+ _E("Can not bind roaming_type %d for preparing statement",
+ quota->roaming_type);
+ error_code = RESOURCED_ERROR_DB_FAILED;
+ goto out;
+ }
+
+ if (sqlite3_bind_text(datausage_quota_insert, 10,
+ quota->imsi_hash, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ _E("Can not bind subscriber_id: %s for preparing statement",
+ quota->imsi_hash);
+ error_code = RESOURCED_ERROR_DB_FAILED;
+ goto out;
+ }
+
+ if (sqlite3_bind_int(datausage_quota_insert, 11,
+ quota->quota_type) != SQLITE_OK) {
+ _E("Can not bind quota_type %d for preparing statement",
+ quota->quota_type);
error_code = RESOURCED_ERROR_DB_FAILED;
goto out;
}
@@ -708,6 +769,8 @@ static resourced_ret_c store_quota(const char *app_id,
error_code = RESOURCED_ERROR_DB_FAILED;
goto out;
}
+
+ *quota_id = sqlite3_last_insert_rowid(resourced_get_database());
out:
sqlite3_reset(datausage_quota_insert);
return error_code;
@@ -719,6 +782,7 @@ static DBusMessage *edbus_create_quota(E_DBus_Object *obj, DBusMessage *msg)
DBusMessageIter iter;
char *app_id = NULL;
+ int quota_id;
struct serialization_quota quota;
struct shared_modules_data *m_data = get_shared_modules_data();
struct counter_arg *carg;
@@ -740,22 +804,24 @@ static DBusMessage *edbus_create_quota(E_DBus_Object *obj, DBusMessage *msg)
goto update_out;
}
- deserialize_quota(msg, &app_id, &quota);
- ret = store_quota(app_id, &quota);
+ if (deserialize_quota(msg, &app_id, &quota) != TRUE) {
+ _E("Cant' deserialize quota");
+ goto update_out;
+ }
+ ret = store_quota(app_id, &quota, &quota_id);
if (ret != RESOURCED_ERROR_NONE) {
_E("Can't store quota!");
goto update_out;
}
- update_quota_state(app_id, quota.iftype, quota.start_time,
- quota.time_period, quota.roaming_type);
+ update_quota_state(app_id, quota_id, &quota);
ret_value_msg_if(!carg->opts,
dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS,
"Counter args is not provided"),
"Please provide valid argument!");
- carg->opts->is_update_quota = 1;
+ SET_BIT(carg->opts->state, RESOURCED_CHECK_QUOTA);
reschedule_count_timer(carg, 0);
_SD("Datausage quota changed");
@@ -823,9 +889,9 @@ static void prepare_response(struct get_stats_context *ctx)
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &info->interval->from);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &info->interval->to);
/* incoming bytes */
- dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &info->foreground.cnt.incoming_bytes);
+ dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &info->cnt.incoming_bytes);
/* outgoing bytes */
- dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &info->foreground.cnt.outgoing_bytes);
+ dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &info->cnt.outgoing_bytes);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &info->roaming);
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &info->hw_net_protocol_type);
@@ -919,24 +985,91 @@ static inline char *_get_public_appid(const uint32_t classid)
static bool need_flush_immediatelly(sig_atomic_t state)
{
- return state & RESOURCED_FORCIBLY_FLUSH_STATE ||
- state & RESOURCED_FORCIBLY_QUIT_STATE;
+ return CHECK_BIT(state, RESOURCED_FORCIBLY_FLUSH_STATE) ||
+ CHECK_BIT(state, RESOURCED_FORCIBLY_QUIT_STATE);
}
-static Eina_Bool _store_and_free_result_cb(void *user_data)
+static void free_restriction_info(void *data)
+{
+ resourced_restriction_info *info = (resourced_restriction_info *)data;
+ if (info->app_id)
+ free((char *)info->app_id);
+ if (info->ifname)
+ free((char *)info->ifname);
+}
+
+static void store_restrictions(struct counter_arg *arg)
+{
+ GSList *rst_list = NULL, *iter = NULL;
+
+ /* find restrictions in nf_cntrs tree, which were active */
+ extract_restriction_list(arg, &rst_list);
+
+ _D("Store restrictions!");
+
+ gslist_for_each_item(iter, rst_list) {
+ resourced_restriction_info *info = (resourced_restriction_info *)iter->data;
+
+ /* when we moved to only one restriction counter,
+ * one of rcv_limit or send_limit value could be
+ * 0, !info->send_limit
+ */
+ if (!info->rcv_limit) {
+ _D("Nothing to store");
+ continue;
+ }
+
+ /* roaming couldn't change without chaning of network interface
+ * undefined behavior here is roaming updated before interface down
+ * we could get here incorrect restriction and fail update it
+ * If it changes before need to keep roaming in nfacct_value
+ */
+ update_restriction_db(info->app_id, info->iftype,
+ info->rcv_limit, info->send_limit,
+ info->rst_state, info->quota_id,
+ info->roaming, info->ifname);
+ }
+
+ g_slist_free_full(rst_list, free_restriction_info);
+}
+
+static bool check_flush_time(time_t flush_period, time_t last_time)
+{
+ time_t cur_time;
+ time(&cur_time);
+ return cur_time - last_time <= flush_period - 1;
+}
+
+static Eina_Bool store_and_free_result_cb(void *user_data)
{
struct counter_arg *arg = (struct counter_arg *)user_data;
+ resourced_ret_c ret;
ret_value_msg_if(!arg, ECORE_CALLBACK_CANCEL, "Please provide valid argument!");
- if (store_result(arg->result, need_flush_immediatelly(arg->opts->state)
- ? 0 : arg->opts->flush_period)) {
+ if (check_flush_time(arg->opts->flush_period, arg->last_run_time) &&
+ !need_flush_immediatelly(arg->opts->state))
+ return ECORE_CALLBACK_CANCEL;
+
+ /* It's dangerouse to store restriction every counting cycle,
+ * 1. we need to request it without reset cmd
+ * 2. we using nf_cntrs, and it case restriction wasn't modified, we
+ * couldn't determine it, and we'll store it
+ * 3. need to fix fill_restriction in answer_func_cb,
+ * to nulify nf_cntrs */
+ if ((CHECK_BIT(arg->opts->state, RESOURCED_FORCIBLY_FLUSH_STATE) ||
+ CHECK_BIT(arg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE)) &&
+ !CHECK_BIT(arg->opts->state, RESOURCED_CHECK_QUOTA))
+ store_restrictions(arg);
+
+ ret = store_result(arg->result);
+ if (ret == RESOURCED_ERROR_NONE) {
/*We still plan to use result outside, just
remove and free elements */
g_tree_ref(arg->result->tree);
free_app_stat_tree(arg->result);
- if (arg->opts->state & RESOURCED_FORCIBLY_FLUSH_STATE) {
- arg->opts->state &= ~RESOURCED_FORCIBLY_FLUSH_STATE;
+ if (CHECK_BIT(arg->opts->state, RESOURCED_UPDATE_REQUESTED)) {
+ UNSET_BIT(arg->opts->state, RESOURCED_UPDATE_REQUESTED);
if (broadcast_edbus_signal(
RESOURCED_PATH_NETWORK,
RESOURCED_INTERFACE_NETWORK,
@@ -947,14 +1080,40 @@ static Eina_Bool _store_and_free_result_cb(void *user_data)
}
arg->store_result_timer = NULL;
+ arg->serialized_counters = 0;
+ time(&(arg->last_run_time));
+
+ /*
+ * it's latest counter code for async operations,
+ * so here could be exit
+ */
+ UNSET_BIT(arg->opts->state, RESOURCED_FORCIBLY_FLUSH_STATE);
+ UNSET_BIT(arg->opts->state, RESOURCED_CHECK_QUOTA);
+
+ /*
+ * timer for quit is scheduled in sig term handler, but it has 1 sec delay,
+ * if we finished early we could quit here
+ */
+ if (CHECK_BIT(arg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE))
+ ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
-static void _store_and_free_result(struct counter_arg *arg)
+static void store_and_free_result(struct counter_arg *arg)
{
+ if (need_flush_immediatelly(arg->opts->state)) {
+ if (arg->store_result_timer)
+ ecore_timer_delay(arg->store_result_timer,
+ 0 - ecore_timer_pending_get(arg->store_result_timer));
+ else
+ arg->store_result_timer = ecore_timer_add(0,
+ store_and_free_result_cb, arg);
+ return;
+ }
+
if (!arg->store_result_timer)
- arg->store_result_timer = ecore_timer_add(STORE_DELAY_INTERVAL,
- _store_and_free_result_cb, arg);
+ arg->store_result_timer = ecore_timer_add(0,
+ store_and_free_result_cb, arg);
}
static void _process_network_counter(struct nl_family_params *params)
@@ -979,34 +1138,23 @@ static void _process_network_counter(struct nl_family_params *params)
netlink->deserialize_answer(&(netlink->params));
- /* process only filled in/out or tethering traffic */
- if ((!g_tree_nnodes(params->carg->in_tree) ||
- !g_tree_nnodes(params->carg->out_tree)) &&
- params->carg->opts->state & RESOURCED_FORCIBLY_QUIT_STATE)
- return;
-
- pthread_rwlock_wrlock(&params->carg->result->guard);
- ret = prepare_application_stat(params->carg->in_tree,
- params->carg->out_tree, params->carg->result,
- params->carg->opts);
- pthread_rwlock_unlock(&params->carg->result->guard);
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to prepare application statistics!");
+ if (!params->carg->serialized_counters &&
+ !CHECK_BIT(params->carg->opts->state,
+ RESOURCED_CHECK_QUOTA)) {
+ /* it could be due, 0 value for all counters
+ * or due 0 payload in netlink response */
+ _D("There is no serialized counters in response");
return;
}
- ret = process_quota(params->carg->result, params->carg->opts);
+
+ ret = process_quota(params->carg);
if (ret != 0) {
_E("Failed to process quota!");
return;
}
- _store_and_free_result(params->carg);
-
- g_tree_ref(params->carg->out_tree);
- free_traffic_stat_tree(params->carg->out_tree);
- g_tree_ref(params->carg->in_tree);
- free_traffic_stat_tree(params->carg->in_tree);
+ store_and_free_result(params->carg);
}
#ifdef CONFIG_DATAUSAGE_NFACCT
@@ -1025,6 +1173,7 @@ static void _process_restriction(struct nl_family_params *cmd)
char *app_id = NULL;
resourced_iface_type iftype;
resourced_restriction_info rst_info = {0,};
+ data_usage_quota du_quota = {0};
resourced_ret_c ret;
_D("Restriction notification");
@@ -1043,16 +1192,19 @@ static void _process_restriction(struct nl_family_params *cmd)
ret_msg_if(ret != RESOURCED_ERROR_NONE,
"Failed to get restriction info!");
+ get_quota_by_id(rst_info.quota_id, &du_quota);
+ _D("quota rcv: %d, send: %d", du_quota.rcv_quota, du_quota.snd_quota);
+
if (notification_type == RESTRICTION_NOTI_C_ACTIVE) {
if (rst_info.quota_id != NONE_QUOTA_ID)
- send_restriction_notification(app_id);
+ send_restriction_notification(app_id, &du_quota);
update_restriction_db(app_id, iftype, 0, 0,
RESOURCED_RESTRICTION_ACTIVATED,
- rst_info.quota_id, rst_info.roaming);
+ rst_info.quota_id, rst_info.roaming, rst_info.ifname);
} else if (notification_type == RESTRICTION_NOTI_C_WARNING) {
/* nested if due error message correctness */
if (rst_info.quota_id != NONE_QUOTA_ID)
- send_restriction_warn_notification(app_id);
+ send_restriction_warn_notification(app_id, &du_quota);
} else
_E("Unkown restriction notification type");
}
@@ -1170,7 +1322,6 @@ release_sock:
}
#endif /* CONFIG_DATAUSAGE_NFACCT */
-
int resourced_init_counter_func(struct counter_arg *carg)
{
int error = 0;
@@ -1186,8 +1337,6 @@ int resourced_init_counter_func(struct counter_arg *carg)
"Couldn't init socket!");
carg->result = create_app_stat_tree();
- carg->in_tree = create_traffic_stat_tree();
- carg->out_tree = create_traffic_stat_tree();
#ifdef CONFIG_DATAUSAGE_NFACCT
carg->nf_cntrs = create_nfacct_tree();
#endif /* CONFIG_DATAUSAGE_NFACCT */
@@ -1236,11 +1385,10 @@ static void finalize_quota_remove(void)
void resourced_finalize_counter_func(struct counter_arg *carg)
{
ret_msg_if(carg == NULL, "Invalid counter argument\n");
- free_traffic_stat_tree(carg->out_tree);
- free_traffic_stat_tree(carg->in_tree);
nulify_app_stat_tree(&carg->result);
ecore_main_fd_handler_del(carg->ecore_fd_handler);
ecore_timer_del(carg->ecore_timer);
+ close(carg->sock);
finalize_quota_insert();
finalize_quota_remove();
}
diff --git a/src/network/counter.c b/src/network/counter.c
index fd436a3e..16dfe278 100644
--- a/src/network/counter.c
+++ b/src/network/counter.c
@@ -41,6 +41,7 @@ struct counter_arg *init_counter_arg(struct daemon_opts *opts)
result->pid = getpid();
#endif
result->opts = opts;
+ result->serialized_counters = 0;
return result;
}
diff --git a/src/network/datausage-common.c b/src/network/datausage-common.c
index 697d5a68..f5e40dd3 100644
--- a/src/network/datausage-common.c
+++ b/src/network/datausage-common.c
@@ -23,13 +23,13 @@
*
*/
-#include "appid-helper.h"
#include "config.h"
#include "const.h"
#include "counter-process.h"
#include "counter.h"
#include "cgroup.h"
#include "datausage-restriction.h"
+#include "db-guard.h"
#include "generic-netlink.h"
#include "net-cls-cgroup.h"
#include "nl-helper.h"
@@ -38,20 +38,24 @@
#include "daemon-options.h"
#include "datausage-common.h"
#include "datausage-quota.h"
+#include "datausage-quota-processing.h"
#include "datausage-vconf-callbacks.h"
#include "iface-cb.h"
#include "macro.h"
#include "module-data.h"
#include "module.h"
#include "nfacct-rule.h"
-#include "protocol-info.h"
#include "resourced.h"
#include "restriction-handler.h"
-#include "roaming.h"
+#include "telephony.h"
+#include "tethering-restriction.h"
#include "storage.h"
#include "trace.h"
#include <linux/rtnetlink.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <Ecore.h>
#ifdef CONFIG_DATAUSAGE_NFACCT
@@ -65,7 +69,8 @@ struct nfacct_key {
u_int32_t classid;
resourced_iface_type iftype;
nfacct_rule_direction iotype;
- char ifname[MAX_NAME_LENGTH];
+ char ifname[MAX_IFACE_LENGTH];
+ nfacct_rule_intend intend;
};
enum nfacct_state {
@@ -73,13 +78,36 @@ enum nfacct_state {
NFACCT_STATE_DEACTIVATED, /* kernel counter was removed, but this counter
is still active, and it will be required for network interface,
when it will be activated */
+ NFACCT_STATE_DEL_DELAYED, /* kernel counters is going to be removed */
};
+typedef enum {
+ NFACCT_FINAL_UNKNOWN,
+ NFACCT_FINAL_REMOVE = 1 << 0,
+} nfacct_finalization;
+
struct nfacct_value {
pid_t pid;
- enum nfacct_state state;
+ enum nfacct_state state; /* used for distinguish incomplete counters,
+ when network interface not yet activated,
+ also for delayed counter deletion,
+ last is not good idea, I hope, to
+ rework it when it will be only one
+ iptable-restore call instead of
+ several*/
+ resourced_ret_c(*iptables_rule)(struct nfacct_rule *counter);
+ nfacct_finalization fini;
+ /* restriction part */
+ u_int64_t quota;
+ int quota_id;
+ resourced_roaming_type roaming;
+ resourced_restriction_state rst_state;
+ /* end restriction part */
+ resourced_state_t ground; /* background/foreground state */
};
+static struct nfacct_value *lookup_counter(struct nfacct_rule *counter);
+
static nfacct_rule_jump get_jump_by_intend(struct nfacct_rule *counter)
{
if (counter->intend == NFACCT_WARN)
@@ -120,15 +148,10 @@ static resourced_ret_c del_iptables_out(struct nfacct_rule *counter)
#endif /* CONFIG_DATAUSAGE_NFACCT */
-static void resourced_roaming_cb_init(void)
-{
- regist_roaming_cb(get_roaming_restriction_cb());
-}
-
static int app_launch_cb(void *data)
{
struct proc_status *p_data = (struct proc_status*)data;
- int ret;
+ resourced_ret_c ret;
ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
"Please provide valid argument!");
ret = join_net_cls(p_data->appid, p_data->pid);
@@ -139,45 +162,51 @@ static int app_launch_cb(void *data)
#ifdef CONFIG_DATAUSAGE_NFACCT
+static int app_launch_srv_cb(void *data)
+{
+ struct proc_status *p_data = (struct proc_status*)data;
+ resourced_ret_c ret;
+ bool background_quota;
+ ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
+ "Please provide valid argument!");
+ ret = join_net_cls(p_data->appid, p_data->pid);
+ if (ret != RESOURCED_ERROR_NONE)
+ _D("Failed to start network counting.");
+ mark_background(p_data->appid);
+
+ background_quota = get_background_quota();
+ if (background_quota)
+ ret = place_pids_to_net_cgroup(p_data->pid, p_data->appid);
+
+ return ret;
+}
+
static int remove_each_counter(
gpointer key,
gpointer value,
gpointer data)
{
struct nfacct_rule *counter = (struct nfacct_rule *)data;
- resourced_iface_type iftype = *(resourced_iface_type *)value;
- struct nfacct_key nf_key;
+ resourced_iface_type iftype = (resourced_iface_type)key;
+ char *ifname = (char *)value;
+ struct nfacct_value *nf_value;
if (iftype == RESOURCED_IFACE_UNKNOWN)
return FALSE;
- nf_key.classid = counter->classid;
- nf_key.iotype = counter->iotype;
- counter->iftype = nf_key.iftype = iftype;
+ counter->iftype = iftype;
+ STRING_SAVE_COPY(counter->ifname, ifname);
- generate_counter_name(counter);
- counter->iptables_rule(counter);
+ nf_value = lookup_counter(counter);
- /* remove from local tree */
-#ifdef DEBUG_ENABLED
- {
- gconstpointer t = g_tree_lookup(counter->carg->nf_cntrs, &nf_key);
- if (t)
- _I("Element exists, remove it!");
- else
- _D("Element doesn't exist!");
- }
-#endif
-
- g_tree_remove(counter->carg->nf_cntrs, &nf_key);
-#ifdef DEBUG_ENABLED
- {
- gconstpointer t = g_tree_lookup(counter->carg->nf_cntrs, &nf_key);
- if (t)
- _E("Element wasn't removed!");
- }
-#endif
+ ret_value_msg_if (!nf_value, FALSE, "Can't remove counter, due it's not in tree");
+ SET_BIT(nf_value->fini, NFACCT_FINAL_REMOVE);
+ /* move it into _answer_func_cb */
+ generate_counter_name(counter);
+ /* request update will be send in produce_net_rule,
+ * just by sending one get request, per name */
+ counter->iptables_rule(counter);
return FALSE;
}
@@ -188,19 +217,18 @@ static void remove_nfacct_counters_for_all_iface(u_int32_t classid, struct count
.iotype = NFACCT_COUNTER_IN,
.iptables_rule = del_iptables_in,
.carg = carg,
+ .ifname = {0},
+ 0,
/* .name until we don't have iftype,
* we couldn't get name */
};
- /* TODO rework for_each_ifindex to avoid cast,
- * right now cast is necessary due for_each_ifindex directy pass
- * given function into g_tree_foreach */
/* remove for ingress counter */
- for_each_ifindex((ifindex_iterator)remove_each_counter, NULL, &counter);
+ for_each_ifnames((ifnames_iterator)remove_each_counter, NULL, &counter);
/* remove for engress counter */
counter.iotype = NFACCT_COUNTER_OUT;
counter.iptables_rule = del_iptables_out;
- for_each_ifindex((ifindex_iterator)remove_each_counter, NULL, &counter);
+ for_each_ifnames((ifnames_iterator)remove_each_counter, NULL, &counter);
}
struct match_nftree_context
@@ -233,6 +261,147 @@ static u_int32_t get_classid_by_pid(struct counter_arg *carg, const pid_t pid)
return ctx.classid;
}
+struct mark_context {
+ u_int32_t classid;
+ resourced_state_t ground;
+ int count;
+ struct counter_arg *carg;
+};
+
+static gboolean mark_ground_by_classid(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct nfacct_key *nf_key = (struct nfacct_key *)key;
+ struct nfacct_value *nf_value = (struct nfacct_value *)value;
+ struct nfacct_rule rule = {.ifname = {0}, 0};
+ struct mark_context *ctx = (struct mark_context *)data;
+ if (nf_key->classid != ctx->classid)
+ return FALSE;
+
+ if (nf_value->ground != ctx->ground) {
+ strcpy(rule.ifname, nf_key->ifname);
+ rule.classid = nf_key->classid;
+ rule.iotype = nf_key->iotype;
+ rule.intend = nf_key->intend;
+ rule.carg = ctx->carg;
+ generate_counter_name(&rule);
+ nf_value->iptables_rule = 0;
+ nfacct_send_get(&rule);
+ nf_value->ground = ctx->ground;
+ }
+
+ if (nf_value->state != NFACCT_STATE_DEACTIVATED)
+ ++ctx->count;
+ return FALSE;
+}
+
+static int mark_ground_state(struct counter_arg *carg, u_int32_t classid,
+ resourced_state_t ground)
+{
+ struct mark_context ctx = {
+ .classid = classid,
+ .ground = ground,
+ .count = 0,
+ .carg = carg};
+ /* find classid in tree */
+ g_tree_foreach(carg->nf_cntrs, mark_ground_by_classid, &ctx);
+ return ctx.count;
+}
+
+void mark_background(const char *app_id)
+{
+ struct shared_modules_data *m_data;
+ struct counter_arg *carg;
+ int nfacct_number = 0;
+
+ u_int32_t classid = get_classid_by_app_id(app_id, false);
+ ret_msg_if(classid == RESOURCED_UNKNOWN_CLASSID,
+ "Unknown classid!");
+ m_data = get_shared_modules_data();
+ ret_msg_if(m_data == NULL, "Can't get module data!");
+
+ carg = m_data->carg;
+ ret_msg_if(carg == NULL, "Cant' get counter arg!");
+
+ nfacct_number = mark_ground_state(carg, classid,
+ RESOURCED_STATE_BACKGROUND);
+ if (!nfacct_number)
+ _D("There is no entry for %s in counter tree", app_id);
+}
+
+static gboolean move_proc_background_cgroup(gpointer key, gpointer value,
+ gpointer data)
+{
+ struct nfacct_value *nf_value = (struct nfacct_value *)value;
+ struct nfacct_key *nf_key = (struct nfacct_key *)key;
+ resourced_state_t state = (resourced_state_t )data;
+
+ if (nf_value->ground != RESOURCED_STATE_BACKGROUND ||
+ nf_key->classid == RESOURCED_ALL_APP_CLASSID ||
+ nf_key->intend != NFACCT_COUNTER)
+ return FALSE;
+
+ /* move into background cgroup */
+ if (state == RESOURCED_STATE_BACKGROUND)
+ place_pids_to_net_cgroup(nf_value->pid, RESOURCED_BACKGROUND_APP_NAME);
+ else {
+ char *app_id = get_app_id_by_classid(nf_key->classid, false);
+ if (app_id)
+ place_pids_to_net_cgroup(nf_value->pid, app_id);
+ }
+ return FALSE;
+}
+
+void foreground_apps(struct counter_arg *carg)
+{
+ g_tree_foreach(carg->nf_cntrs, move_proc_background_cgroup, (void *)RESOURCED_STATE_FOREGROUND);
+}
+
+void background_apps(struct counter_arg *carg)
+{
+ g_tree_foreach(carg->nf_cntrs, move_proc_background_cgroup, (void *)RESOURCED_STATE_BACKGROUND);
+}
+
+static int app_resume_cb(void *data)
+{
+ struct proc_status *p_data = (struct proc_status*)data;
+ struct shared_modules_data *m_data;
+ struct counter_arg *carg;
+ u_int32_t classid;
+ resourced_ret_c ret = RESOURCED_ERROR_NONE;
+ int nfacct_number = 0;
+ bool background_quota = false;
+
+ ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
+ "Please provide valid argument!");
+
+ m_data = get_shared_modules_data();
+ ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
+ "Can't get module data!");
+
+ carg = m_data->carg;
+ ret_value_msg_if(carg == NULL, RESOURCED_ERROR_FAIL,
+ "Cant' get counter arg!");
+ classid = get_classid_by_pid(carg, p_data->pid);
+ ret_value_msg_if(classid == RESOURCED_UNKNOWN_CLASSID,
+ RESOURCED_ERROR_FAIL, "No classid to terminate!");
+
+ /* find in tree nf_cntr and mark it as background */
+
+ nfacct_number = mark_ground_state(carg, classid,
+ RESOURCED_STATE_FOREGROUND);
+ background_quota = get_background_quota();
+ if (!nfacct_number) {
+ ret = join_net_cls(p_data->appid, p_data->pid);
+ if (ret != RESOURCED_ERROR_NONE)
+ _D("Failed to start network counting.");
+
+ } else if(background_quota)
+ place_pids_to_net_cgroup(p_data->pid, p_data->appid);
+
+ return ret;
+}
+
static int app_terminate_cb(void *data)
{
struct proc_status *p_data = (struct proc_status*)data;
@@ -257,6 +426,53 @@ static int app_terminate_cb(void *data)
return RESOURCED_ERROR_NONE;
}
+resourced_state_t get_app_ground(struct nfacct_rule *counter)
+{
+ struct nfacct_value *nf_value = lookup_counter(counter);
+ return nf_value ? nf_value->ground : RESOURCED_STATE_UNKNOWN;
+}
+
+static int app_backgrnd_cb(void *data)
+{
+ struct proc_status *p_data = (struct proc_status*)data;
+ struct shared_modules_data *m_data;
+ struct counter_arg *carg;
+ u_int32_t classid;
+ int nfacct_number = 0;
+ bool background_quota = false;
+ ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
+ "Please provide valid argument!");
+
+ m_data = get_shared_modules_data();
+ ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
+ "Can't get module data!");
+
+ carg = m_data->carg;
+ ret_value_msg_if(carg == NULL, RESOURCED_ERROR_FAIL,
+ "Cant' get counter arg!");
+ classid = get_classid_by_pid(carg, p_data->pid);
+ ret_value_msg_if(classid == RESOURCED_UNKNOWN_CLASSID,
+ RESOURCED_ERROR_FAIL, "No classid to terminate!");
+
+ /* find in tree nf_cntr and mark it as background */
+
+ nfacct_number = mark_ground_state(carg, classid,
+ RESOURCED_STATE_BACKGROUND);
+ if (nfacct_number) {
+ background_quota = get_background_quota();
+ /* if we have applied background quota, put current pid into
+ * background cgroup */
+ if (background_quota)
+ place_pids_to_net_cgroup(p_data->pid, RESOURCED_BACKGROUND_APP_NAME);
+ }
+
+ if (!nfacct_number)
+ _D("There wasn't any information about background application "\
+ "in nfacct counters tree");
+ return RESOURCED_ERROR_NONE;
+}
+
+
static gboolean populate_classid_tree(gpointer key,
gpointer value,
gpointer data)
@@ -292,7 +508,8 @@ static int add_one_tizen_os_counter(
{
struct counter_arg *carg = (struct counter_arg *)data;
struct nfacct_rule counter = {.name = {0}, .ifname = {0}, 0};
- resourced_iface_type iftype = *(resourced_iface_type *)value;
+ resourced_iface_type iftype = (resourced_iface_type)key;
+ char *ifname = (char *)value;
if (iftype <= RESOURCED_IFACE_UNKNOWN ||
iftype >= RESOURCED_IFACE_LAST_ELEM)
@@ -301,17 +518,22 @@ static int add_one_tizen_os_counter(
counter.iotype = NFACCT_COUNTER_IN;
counter.iftype = iftype;
counter.carg = carg;
+ STRING_SAVE_COPY(counter.ifname, ifname);
generate_counter_name(&counter);
- add_iptables_in(&counter);
+ if (add_iptables_in(&counter) != RESOURCED_ERROR_NONE)
+ _D("Failed to add counter %s", counter.name);
+
counter.iotype = NFACCT_COUNTER_OUT;
generate_counter_name(&counter);
- add_iptables_out(&counter);
+ if (add_iptables_out(&counter) != RESOURCED_ERROR_NONE)
+ _D("Failed to add counter %s", counter.name);
+
return FALSE;
}
static void add_tizen_os_counters(struct counter_arg *carg) {
- for_each_ifindex((ifindex_iterator)add_one_tizen_os_counter, NULL, carg);
+ for_each_ifnames((ifnames_iterator)add_one_tizen_os_counter, NULL, carg);
}
static void reload_all_nf_counters(struct counter_arg *carg)
@@ -367,8 +589,9 @@ static inline char *get_public_appid(const uint32_t classid)
/* following value for ALL is suitable for using in statistics
what's why it's not in get_app_id_by_classid */
- if (classid == RESOURCED_ALL_APP_CLASSID)
- return RESOURCED_ALL_APP;
+ if (classid == RESOURCED_ALL_APP_CLASSID ||
+ classid == RESOURCED_BACKGROUND_APP_CLASSID)
+ return strdup(RESOURCED_ALL_APP);
appid = get_app_id_by_classid(classid, true);
return !appid ? UNKNOWN_APP : appid;
@@ -384,6 +607,7 @@ static void init_nfacct(u_int32_t classid, pid_t pid,
counter->pid = pid;
counter->intend = NFACCT_COUNTER;
counter->quota = 0;
+ counter->roaming = get_current_roaming();
if (ctype == NFACCT_COUNTER_IN)
counter->iptables_rule = add_iptables_in;
else if (ctype == NFACCT_COUNTER_OUT)
@@ -397,6 +621,39 @@ static resourced_ret_c del_counter(struct nfacct_rule *counter)
counter->iotype);
}
+static void fill_du_quota(const char *app_id, const char *ifname,
+ const resourced_iface_type iftype, data_usage_quota *du_quota,
+ int *quota_id, resourced_state_t ground)
+{
+ char *imsi_hash = get_imsi_hash(get_current_modem_imsi());
+ resourced_roaming_type roaming = get_current_roaming();
+ /* lookup in quota tree */
+ resourced_ret_c ret = get_quota_by_appid(app_id, imsi_hash, iftype,
+ roaming, du_quota, quota_id, ground);
+
+ du_quota->roaming_type = roaming;
+ _D("ret %d, quota id %d", ret, *quota_id);
+ /* if lookup wasn't successfull, searchin restriction db,
+ * for example we could faced with restriction without quota */
+ if (ret != RESOURCED_ERROR_NONE || !*quota_id) {
+ resourced_restriction_info rst_info = {0};
+ resourced_ret_c ret;
+ rst_info.ifname = ifname;
+ /* TODO add roaming into restriction info request */
+ ret = get_restriction_info(app_id, iftype, &rst_info);
+ ret_msg_if(ret != RESOURCED_ERROR_NONE,
+ "Failed to get restriction info!");
+
+ get_quota_by_id(rst_info.quota_id, du_quota);
+ du_quota->roaming_type = rst_info.roaming;
+ *quota_id = rst_info.quota_id;
+ }
+ _D("quota rcv: % " PRId64 ", send: % " PRId64 " ", du_quota->rcv_quota,
+ du_quota->snd_quota);
+ _D("quota roaming: %d", du_quota->roaming_type);
+
+}
+
static int fill_restriction(struct rtattr *attr_list[__NFACCT_MAX],
void *user_data)
{
@@ -404,18 +661,26 @@ static int fill_restriction(struct rtattr *attr_list[__NFACCT_MAX],
struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
char *cnt_name = (char *)RTA_DATA(
attr_list[NFACCT_NAME]);
+
+ /* because foreground/background property wasn't
+ * in counter */
+ resourced_state_t ground;
char *app_id = 0;
+ int quota_id = 0;
int ret = 0;
- resourced_restriction_info rst_info = {0};
+ data_usage_quota du_quota = {0};
init_nfacct(0, 0, 0, carg, &counter);
strcpy(counter.name, cnt_name);
recreate_counter_by_name(cnt_name, &counter);
+ ground = counter.classid == RESOURCED_BACKGROUND_APP_CLASSID ?
+ RESOURCED_STATE_BACKGROUND : RESOURCED_STATE_FOREGROUND;
app_id = get_public_appid(counter.classid);
- ret = get_restriction_info(app_id, counter.iftype, &rst_info);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "Failed to get restriction info!");
+ ret_value_msg_if(!app_id, RESOURCED_ERROR_NONE, "Unknown app_id for %d",
+ counter.classid);
+ fill_du_quota(app_id, counter.ifname, counter.iftype, &du_quota,
+ &quota_id, ground);
if (counter.intend == NFACCT_BLOCK) {
if (counter.iotype == NFACCT_COUNTER_IN) {
@@ -434,17 +699,23 @@ static int fill_restriction(struct rtattr *attr_list[__NFACCT_MAX],
* not yet fired rule */
ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
"Can't create auxilary counter %s", out_counter.name);
+ ret = apply_tethering_restriction(RST_SET);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "Can't block tethering");
}
- if (rst_info.quota_id != NONE_QUOTA_ID)
- send_restriction_notification(app_id);
+ /* send restriction notification only in case of
+ * it was related to quota */
+ if (quota_id != NONE_QUOTA_ID)
+ send_restriction_notification(app_id, &du_quota);
+ else
+ _D("No need to send restriction notification");
update_restriction_db(app_id, counter.iftype, 0, 0,
RESOURCED_RESTRICTION_ACTIVATED,
- rst_info.quota_id, rst_info.roaming);
-
+ quota_id, du_quota.roaming_type, counter.ifname);
} else if (counter.intend == NFACCT_WARN) {
- if (rst_info.quota_id != NONE_QUOTA_ID)
- send_restriction_warn_notification(app_id);
+ if (quota_id != NONE_QUOTA_ID)
+ send_restriction_warn_notification(app_id, &du_quota);
/* remove both warnings */
counter.iotype = NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT;
ret = del_counter(&counter);
@@ -532,6 +803,16 @@ static void fini_notifier(struct counter_arg *carg)
/* end notification section */
#else
+static int app_launch_srv_cb(void *data)
+{
+ return 0;
+}
+
+static int app_resume_cb(void *data)
+{
+ return 0;
+}
+
static int app_terminate_cb(void *data)
{
return 0;
@@ -558,19 +839,21 @@ static int resourced_datausage_init(void *data)
"Invalid shared modules data\n");
/* register notifier cb */
register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, app_launch_cb);
- register_notifier(RESOURCED_NOTIFIER_APP_RESUME, app_launch_cb);
- register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, app_launch_cb);
+ register_notifier(RESOURCED_NOTIFIER_APP_RESUME, app_resume_cb);
+ register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, app_launch_srv_cb);
register_notifier(RESOURCED_NOTIFIER_APP_TERMINATE, app_terminate_cb);
+ register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, app_backgrnd_cb);
m_data->carg = init_counter_arg(marg->opts);
ret_code = resourced_iface_init();
ret_value_msg_if(ret_code < 0, ret_code, "resourced_iface_init failed");
- resourced_roaming_cb_init();
ret_code = resourced_init_counter_func(m_data->carg);
ret_value_msg_if(ret_code < 0, ret_code, "Error init counter func\n");
resourced_add_vconf_datausage_cb(m_data->carg);
- init_hw_net_protocol_type();
reactivate_restrictions();
+ ret_code = resourced_init_db_guard(m_data->carg);
+ ret_value_msg_if(ret_code < 0, ret_code, "Error init db guard\n");
+
#ifdef CONFIG_DATAUSAGE_NFACCT
reload_all_nf_counters(m_data->carg);
@@ -596,13 +879,14 @@ static int resourced_datausage_finalize(void *data)
resourced_finalize_counter_func(m_data->carg);
finalize_carg(m_data->carg);
finalize_storage_stm();
- finalize_hw_net_protocol_type();
unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, app_launch_cb);
unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, app_launch_cb);
unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, app_launch_cb);
unregister_notifier(RESOURCED_NOTIFIER_APP_TERMINATE, app_terminate_cb);
resourced_iface_finalize();
finalize_iftypes();
+ finilize_telephony();
+ ecore_timer_del(m_data->carg->erase_timer);
return RESOURCED_ERROR_NONE;
}
@@ -624,12 +908,23 @@ static int compare_nfcntr(gconstpointer a, gconstpointer b,
ret = key_a->iotype - key_b->iotype;
if (ret)
return ret;
- return strcmp(key_a->ifname, key_b->ifname);
+
+ ret = key_a->intend - key_b->intend;
+ if (ret)
+ return ret;
+
+ /* in case of incomplete counters ->ifname will contain
+ * empty string, if we found incomplete counter,
+ * assume it's the same as given ifname */
+ if (strlen(key_a->ifname) && strlen(key_b->ifname))
+ return strcmp(key_a->ifname, key_b->ifname);
+
+ return 0;
}
GTree *create_nfacct_tree(void)
{
- return g_tree_new_full(compare_nfcntr, NULL, NULL, free);
+ return g_tree_new_full(compare_nfcntr, NULL, free, free);
}
static struct nfacct_value *lookup_counter(struct nfacct_rule *counter)
@@ -637,8 +932,10 @@ static struct nfacct_value *lookup_counter(struct nfacct_rule *counter)
struct nfacct_key key = {
.classid = counter->classid,
.iftype = counter->iftype,
- .iotype = counter->iotype
+ .iotype = counter->iotype,
+ .intend = counter->intend,
};
+
STRING_SAVE_COPY(key.ifname, counter->ifname);
return (struct nfacct_value *)g_tree_lookup(counter->carg->nf_cntrs,
@@ -649,73 +946,235 @@ static struct nfacct_value *lookup_counter(struct nfacct_rule *counter)
void keep_counter(struct nfacct_rule *counter)
{
struct nfacct_key *key = NULL;
- struct nfacct_value *value = NULL;
+ struct nfacct_value *value = lookup_counter(counter);
- key = (struct nfacct_key *)malloc(sizeof(
- struct nfacct_key));
- ret_msg_if(key == NULL,
- "Can allocate memory for nfacct_key!");
+ if (!value) {
+ key = (struct nfacct_key *)malloc(sizeof(
+ struct nfacct_key));
+ ret_msg_if(key == NULL,
+ "Can allocate memory for nfacct_key!");
- value = (struct nfacct_value *)malloc(sizeof(
- struct nfacct_value));
+ value = (struct nfacct_value *)malloc(sizeof(
+ struct nfacct_value));
- if (value == NULL) {
- free(key);
- _D("Can allocate memory for nfacct_key!");
- return;
+ if (value == NULL) {
+ free(key);
+ _D("Can allocate memory for nfacct_key!");
+ return;
+ }
+ key->classid = counter->classid;
+ key->iftype = counter->iftype;
+ key->iotype = counter->iotype;
+ key->intend = counter->intend;
+ STRING_SAVE_COPY(key->ifname, counter->ifname);
+ g_tree_insert(counter->carg->nf_cntrs, key, value);
}
- key->classid = counter->classid;
- key->iftype = counter->iftype;
- key->iotype = counter->iotype;
- STRING_SAVE_COPY(key->ifname, counter->ifname);
-
value->pid = counter->pid;
value->state = NFACCT_STATE_ACTIVE;
+ value->quota = counter->quota;
+ value->iptables_rule = counter->iptables_rule;
+ value->quota_id = counter->quota_id;
+ value->rst_state = counter->rst_state;
+ value->roaming = counter->roaming;
+ value->fini = 0;
+ value->ground = RESOURCED_STATE_FOREGROUND;
+
+#ifdef DEBUG_ENABLED
+ if (key && key->intend == NFACCT_BLOCK)
+ _D("%p rst_state: %d", value, value->rst_state);
+#endif
+}
+
+void finalize_counter(struct nfacct_rule *counter)
+{
+ resourced_ret_c ret;
+ struct nfacct_key nf_key = {
+ .classid = counter->classid,
+ .iftype = counter->iftype,
+ .iotype = counter->iotype,
+ .intend = counter->intend,
+ };
+ struct nfacct_value *value;
+
+ STRING_SAVE_COPY(nf_key.ifname, counter->ifname);
+ value = (struct nfacct_value *)g_tree_lookup(counter->carg->nf_cntrs,
+ &nf_key);
+
+#ifdef DEBUG_ENABLED
+ _D("counter name: %s", counter->name);
+ _D("counter classid: %d", counter->classid);
+ _D("counter iftype: %d", counter->iftype);
+ _D("counter iotype: %d", counter->iotype);
+ _D("counter ifname: %s", counter->ifname);
+#endif /* DEBUG_ENABLED */
+
+ ret_msg_if(!value, "Can't find counter", counter->name);
+ if (!CHECK_BIT(value->fini, NFACCT_FINAL_REMOVE)) {
+#ifdef DEBUG_ENABLED
+ _D("No need to remove value %p", value);
+#endif
+ return;
+ }
+#ifdef DEBUG_ENABLED
+ else {
+ _D("remove value %p", value);
+ }
+#endif
+ ret_msg_if(!value->iptables_rule, "There is no iptables_rule handler");
+
+ ret = value->iptables_rule(counter);
+ ret_msg_if (ret != RESOURCED_ERROR_NONE, "Failed to execute iptables rule");
+ UNSET_BIT(value->fini, NFACCT_FINAL_REMOVE);
+ value->state = NFACCT_STATE_DEACTIVATED;
+#ifdef DEBUG_ENABLED
+ if (nf_key.intend == NFACCT_BLOCK)
+ _D("%p rst_state: %d", value, value->rst_state);
+#endif
+}
+
+void set_finalize_flag(struct nfacct_rule *counter)
+{
+ struct nfacct_key nf_key = {
+ .classid = counter->classid,
+ .iftype = counter->iftype,
+ .iotype = counter->iotype,
+ .intend = counter->intend,
+ };
+ struct nfacct_value *value;
+
+ STRING_SAVE_COPY(nf_key.ifname, counter->ifname);
+ value = lookup_counter(counter);
+ ret_msg_if(!value, "Can't find counter for set finalize state!");
+ SET_BIT(value->fini, NFACCT_FINAL_REMOVE);
+ value->iptables_rule = nfacct_send_del;
+ value->rst_state = counter->rst_state;
+#ifdef DEBUG_ENABLED
+ if (nf_key.intend == NFACCT_BLOCK)
+ _D("%p rst_state: %d", value, value->rst_state);
+#endif
+ if (counter->carg && counter->carg->opts)
+ SET_BIT(counter->carg->opts->state, RESOURCED_FORCIBLY_FLUSH_STATE);
+}
+
+static gboolean fill_restriction_list(gpointer key, gpointer value,
+ gpointer data)
+{
+ GSList **rst_list = (GSList **)data;
+ GSList *iter = NULL;
+ resourced_restriction_info *info = NULL;
+
+ struct nfacct_key *nf_key = (struct nfacct_key *)key;
+ struct nfacct_value *nf_value = (struct nfacct_value *)value;
+ char *app_id;
+
+ /* only restriction guard is needed here */
+ if (nf_key->intend != NFACCT_BLOCK)
+ return FALSE;
+
+ app_id = get_public_appid(nf_key->classid);
+ ret_value_msg_if(!app_id, FALSE, "Can't get appid");
+
+ gslist_for_each_item(iter, *rst_list) {
+ resourced_restriction_info *look_info = (resourced_restriction_info *)iter->data;
+ if (look_info->app_id && !strcmp(look_info->app_id, app_id) &&
+ look_info->iftype == nf_key->iftype &&
+ look_info->quota_id == nf_value->quota_id &&
+ look_info->roaming == nf_value->roaming) {
+ info = look_info;
+ break;
+ }
+ }
+
+ if (!info) {
+ _D("We didn't find this restriction in list! Create new one!");
+ info = (resourced_restriction_info *)malloc(sizeof(resourced_restriction_info));
+ ret_value_msg_if (!info, FALSE, "Can't allocate memory");
+ memset(info, 0, sizeof(resourced_restriction_info));
+ *rst_list = g_slist_prepend(*rst_list, info);
+ }
+
+#ifdef DEBUG_ENABLED
+ if (nf_key->intend == NFACCT_BLOCK)
+ _D("%p rst_state: %d", nf_value, nf_value->rst_state);
+#endif
- g_tree_insert(counter->carg->nf_cntrs, key, value);
+ if (info->iftype == RESOURCED_IFACE_UNKNOWN)
+ info->iftype = nf_key->iftype;
+ if (info->quota_id == NONE_QUOTA_ID)
+ info->quota_id = nf_value->quota_id;
+ if (info->roaming == RESOURCED_ROAMING_UNKNOWN)
+ info->roaming = nf_value->roaming;
+ if (!info->ifname)
+ info->ifname = strdup(nf_key->ifname);
+ if (!info->app_id)
+ info->app_id = app_id;
+ if (!info->rst_state)
+ info->rst_state = nf_value->rst_state == RESOURCED_RESTRICTION_REMOVED ? RESOURCED_RESTRICTION_ACTIVATED : nf_value->rst_state;
+
+ if (nf_key->iotype == NFACCT_COUNTER_IN)
+ info->rcv_limit = nf_value->quota;
+ else if(nf_key->iotype == NFACCT_COUNTER_OUT)
+ info->send_limit = nf_value->quota;
+ else
+ _D("Unknown iotype");
+
+ return FALSE;
+}
+
+void extract_restriction_list(struct counter_arg *arg,
+ GSList **rst_list)
+{
+ /* to avoid duplication and search while filling rst_list */
+ g_tree_foreach(arg->nf_cntrs, fill_restriction_list, rst_list);
+}
+
+void update_counter_quota_value(struct nfacct_rule *counter, uint64_t bytes)
+{
+ struct nfacct_value *value = lookup_counter(counter);
+ ret_msg_if(!value, "Can't find nfacct entry for %s", counter->name);
+ if (value->quota <= bytes) {
+ _D("overquoted % " PRIu64 " ", bytes);
+ value->quota = 0;
+ } else
+ value->quota -= bytes;
}
static int create_each_iptable_rule(gpointer key, gpointer value, void *data)
{
struct make_rule_context *ctx = (struct make_rule_context *)data;
resourced_ret_c ret;
- resourced_iface_type iftype = *(resourced_iface_type *)value;
+ resourced_iface_type iftype = (resourced_iface_type)key;
+ char *ifname = (char *)value;
struct nfacct_value *counter = NULL;
if (iftype <= RESOURCED_IFACE_UNKNOWN ||
- iftype >= RESOURCED_IFACE_LAST_ELEM) {
+ iftype >= RESOURCED_IFACE_LAST_ELEM ||
+ iftype == RESOURCED_IFACE_BLUETOOTH) {
_D("Unsupported network interface type %d",
iftype);
return RESOURCED_ERROR_NONE;
}
ctx->counter->iftype = iftype;
+ STRING_SAVE_COPY(ctx->counter->ifname, ifname);
generate_counter_name(ctx->counter);
counter = lookup_counter(ctx->counter);
- if (counter != NULL) {
- _D("Counter already exists!");
- return RESOURCED_ERROR_NONE;
+ if (!counter ||
+ (counter->state != NFACCT_STATE_ACTIVE)) {
+ ret = ctx->counter->iptables_rule(ctx->counter);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, RESOURCED_ERROR_FAIL,
+ "Can't add iptables ingress rule");
}
- ret = ctx->counter->iptables_rule(ctx->counter);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, RESOURCED_ERROR_FAIL,
- "Can't add iptables ingress rule");
- keep_counter(ctx->counter);
return RESOURCED_ERROR_NONE;
}
static void populate_incomplete_counter(void *data)
{
struct make_rule_context *ctx = (struct make_rule_context *)data;
- struct nfacct_value *counter;
generate_counter_name(ctx->counter);
- counter = lookup_counter(ctx->counter);
- if (counter != NULL) {
- _D("Counter already exists!");
- return;
- }
keep_counter(ctx->counter);
}
@@ -731,12 +1190,12 @@ static resourced_ret_c create_iptables_rule(const char *app_id, const pid_t pid)
ctx.counter = &counter;
init_nfacct(classid, pid, NFACCT_COUNTER_IN, carg, &counter);
- for_each_ifindex((ifindex_iterator)create_each_iptable_rule,
+ for_each_ifnames((ifnames_iterator)create_each_iptable_rule,
populate_incomplete_counter, &ctx);
counter.iotype = NFACCT_COUNTER_OUT;
counter.iptables_rule = add_iptables_out;
- for_each_ifindex((ifindex_iterator)create_each_iptable_rule,
+ for_each_ifnames((ifnames_iterator)create_each_iptable_rule,
populate_incomplete_counter, &ctx);
return RESOURCED_ERROR_NONE;
@@ -755,6 +1214,27 @@ static bool is_incomplete_counter(struct nfacct_key *nfacct_key, struct nfacct_v
/* special incomplete status unnecessary */
}
+static void trace_nf_key_value(struct nfacct_key *nfacct_key, struct nfacct_value *nfacct_value)
+{
+#ifdef DEBUG_ENABLED
+ _D("-------- NF TREE NODE -----------");
+ _D("classid: %d", nfacct_key->classid);
+ _D("iftype: %d", nfacct_key->iftype);
+ _D("iotype: %d", nfacct_key->iotype);
+ _D("ifname: %s", nfacct_key->ifname);
+ _D("pid: %d", nfacct_value->pid);
+ _D("state: %d", nfacct_value->state);
+ _D("fini: %d", nfacct_value->fini);
+ _D("intend: %d", nfacct_key->intend);
+ _D("quota: %" PRIu64 " ", nfacct_value->quota);
+ _D("quota_id:%d", nfacct_value->quota_id);
+ _D("roaming: %d", nfacct_value->roaming);
+ if (nfacct_key->intend == NFACCT_BLOCK)
+ _D("%p rst_state:%d", nfacct_value, nfacct_value->rst_state);
+ _D("---------NF TREE NODE -----------");
+#endif /* DEBUG_ENABLED */
+}
+
static gboolean activate_each_counter_by_iftype(gpointer key,
gpointer value,
gpointer data)
@@ -766,6 +1246,18 @@ static gboolean activate_each_counter_by_iftype(gpointer key,
struct nfacct_value *found_counter;
int ret = RESOURCED_ERROR_NONE;
+
+ trace_nf_key_value(nfacct_key, nfacct_value);
+ /* skip restriction and warning here due there is special
+ * logic for it in restriction-handler.c,
+ * maybe it worth to merge that logic and remove
+ * handler in restriction-handler, but need to take
+ * imsi into account */
+ if (nfacct_key->intend == NFACCT_BLOCK ||
+ nfacct_key->intend == NFACCT_WARN) {
+ _D("skip block and warning");
+ return FALSE;
+ }
/* ugly check, due in case of RMNET -> WLAN switch,
* WLAN activated before then RMNET is deactivated */
@@ -787,6 +1279,15 @@ static gboolean activate_each_counter_by_iftype(gpointer key,
* WLAN is preffered, so lets deactivate it */
return FALSE; /* continue iteration */
+ /* counter still active it wasn't yet removed,
+ * del_counter_delayed isn't yet called */
+ if (nfacct_value->state == NFACCT_STATE_DEL_DELAYED &&
+ ctx->iftype == nfacct_key->iftype) {
+ /* in del_counter_delayed we'll free context
+ * and skip removing */
+ nfacct_value->state = NFACCT_STATE_ACTIVE;
+ return FALSE;
+ }
counter.classid = nfacct_key->classid;
counter.iotype = nfacct_key->iotype;
@@ -815,8 +1316,6 @@ static gboolean activate_each_counter_by_iftype(gpointer key,
if (found_counter != NULL && found_counter->state ==
NFACCT_STATE_DEACTIVATED)
found_counter->state = NFACCT_STATE_ACTIVE;
- else
- keep_counter(&counter);
return FALSE;
}
@@ -838,7 +1337,7 @@ static void handle_on_iface_up(const int ifindex)
ctx.iftype = iftype;
ctx.carg = m_data->carg;
g_tree_foreach(ctx.carg->nf_cntrs, activate_each_counter_by_iftype, &ctx);
- add_tizen_os_counters(m_data->carg);
+ add_one_tizen_os_counter((gpointer)iftype, NULL, m_data->carg);
}
struct del_counter_context
@@ -855,6 +1354,10 @@ static Eina_Bool del_counter_delayed(void *data)
struct del_counter_context *del_ctx = (struct del_counter_context *)data;
struct nfacct_value *nfacct_value = del_ctx->nfacct_value;
struct nfacct_key *nfacct_key = del_ctx->nfacct_key;
+ if (nfacct_value->state != NFACCT_STATE_DEL_DELAYED) {
+ _D("nfacct counter state is %d", nfacct_value->state);
+ goto out;
+ }
counter.classid = nfacct_key->classid;
counter.iotype = nfacct_key->iotype;
@@ -866,12 +1369,16 @@ static Eina_Bool del_counter_delayed(void *data)
ret = del_counter(&counter);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ECORE_CALLBACK_CANCEL,
- "Can't delete counter %s",
- counter.name);
+ if(ret != RESOURCED_ERROR_NONE) {
+ _E("Can't delete counter %s",
+ counter.name);
+ goto out;
+ }
nfacct_value->state = NFACCT_STATE_DEACTIVATED;
+out:
+ free(del_ctx);
return ECORE_CALLBACK_CANCEL;
}
@@ -884,8 +1391,12 @@ static gboolean deactivate_each_counter_by_iftype(gpointer key,
struct iftype_context *ctx = (struct iftype_context *)data;
struct del_counter_context *del_ctx = NULL;
- /* deactivate counters only for ctx->iftype interface */
- if (ctx->iftype != nfacct_key->iftype)
+ /* deactivate counters only for ctx->iftype interface,
+ * and only counters warning/restriction will be removed in
+ * another _reset_restriction_iter */
+ if (ctx->iftype != nfacct_key->iftype ||
+ nfacct_key->intend == NFACCT_WARN ||
+ nfacct_key->intend == NFACCT_BLOCK)
return FALSE; /* continue iteration */
del_ctx = (struct del_counter_context *)malloc(
@@ -895,6 +1406,7 @@ static gboolean deactivate_each_counter_by_iftype(gpointer key,
del_ctx->nfacct_key = nfacct_key;
del_ctx->nfacct_value = nfacct_value;
del_ctx->carg = ctx->carg;
+ nfacct_value->state = NFACCT_STATE_DEL_DELAYED;
ecore_timer_add(0, del_counter_delayed, del_ctx);
return FALSE;
@@ -941,9 +1453,9 @@ iface_callback *create_counter_callback(void)
resourced_ret_c join_net_cls(const char *app_id, const pid_t pid)
{
resourced_ret_c ret;
- char pkgname[MAX_PATH_LENGTH];
- extract_pkgname(app_id, pkgname, sizeof(pkgname));
- ret = make_net_cls_cgroup_with_pid(pid, pkgname);
+ ret_value_msg_if(!app_id, RESOURCED_ERROR_INVALID_PARAMETER,
+ "invalid app_id");
+ ret = make_net_cls_cgroup_with_pid(pid, app_id);
ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
ret = update_classids();
ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
diff --git a/src/network/datausage-quota-processing.c b/src/network/datausage-quota-processing.c
index 11822b49..069d85a4 100644
--- a/src/network/datausage-quota-processing.c
+++ b/src/network/datausage-quota-processing.c
@@ -34,17 +34,20 @@
#include <sqlite3.h>
#include <inttypes.h>
+#include "counter.h"
#include "database.h"
#include "data_usage.h"
#include "macro.h"
-#include "protocol-info.h"
#include "resourced.h"
+#include "net-cls-cgroup.h"
#include "notification.h"
#include "storage.h"
#include "trace.h"
-#include "roaming.h"
+#include "telephony.h"
+#include "datausage-common.h"
#include "datausage-restriction.h"
#include "datausage-vconf-common.h"
+#include "datausage-quota-processing.h"
static GTree *quotas;
static sqlite3_stmt *select_stmt;
@@ -58,20 +61,23 @@ static const char select_query[] = "SELECT qt.binpath, qt.sent_quota, qt.rcv_quo
"efq.finish_time AS effective_finish, qt.iftype AS iftype, " \
"qt.roaming, "\
"efq.state, "\
- "qt.ROWID "\
+ "qt.ROWID, "\
+ "qt.imsi, "\
+ "qt.ground "\
"FROM quotas AS qt "\
"LEFT OUTER JOIN effective_quotas AS efq ON (qt.binpath = efq.binpath "\
- "AND qt.iftype = efq.iftype AND qt.roaming = efq.roaming) "\
+ "AND qt.iftype = efq.iftype AND qt.roaming = efq.roaming "\
+ "AND qt.imsi = efq.imsi) "\
"GROUP BY qt.binpath, qt.iftype, qt.sent_quota, qt.rcv_quota, " \
- "qt.roaming";
+ "qt.roaming, qt.imsi";
static const char insert_query[] = "REPLACE INTO effective_quotas " \
"(binpath, sent_used_quota, rcv_used_quota, " \
- "start_time, finish_time, iftype, roaming, state) " \
- " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+ "start_time, finish_time, iftype, roaming, state, imsi) " \
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
static const char clear_effective_quota_query[] = "DELETE FROM effective_quotas " \
- " WHERE binpath = ? AND iftype = ? AND roaming = ?";
+ " WHERE binpath = ? AND iftype = ? AND roaming = ? AND imsi = ?";
enum resourced_quota_state {
RESOURCED_QUOTA_UNKNOWN, /**< undefined/initial state */
@@ -98,6 +104,8 @@ struct quota_key {
const char *app_id;
resourced_iface_type iftype;
resourced_roaming_type roaming;
+ const char *imsi_hash;
+ resourced_state_t ground;
};
typedef enum {
@@ -106,33 +114,35 @@ typedef enum {
DROP_NO_NEED = 2
} drop_decision;
-static void obtain_and_keep_quotas(sqlite3_stmt *query)
+static inline bool check_imsi_hash(const char *hash_a, const char *hash_b);
+
+static resourced_ret_c obtain_and_keep_quotas(sqlite3_stmt *query)
{
int rc = 0;
+ resourced_ret_c ret = RESOURCED_ERROR_NONE;
struct quota *value = 0;
struct quota_key *key = 0;
- if (!query) {
- _D("Can not update quotas: empty query");
- return;
- }
+ ret_value_msg_if(!query, RESOURCED_ERROR_INVALID_PARAMETER,
+ "Can not update quotas: empty query");
do {
rc = sqlite3_step(query);
if (rc == SQLITE_ERROR) {
_E("Error updating quotas %s", sqlite3_errmsg(resourced_get_database()));
- return;
+ return RESOURCED_ERROR_DB_FAILED;
} else if (rc == SQLITE_ROW) {
value = g_new0(struct quota, 1);
if (!value) {
_E("Can't allocate value for quota");
- return;
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
}
key = g_new0(struct quota_key, 1);
if (!key) {
_E("Can't allocate key for quota");
+ ret = RESOURCED_ERROR_OUT_OF_MEMORY;
goto free_value;
}
@@ -142,6 +152,9 @@ static void obtain_and_keep_quotas(sqlite3_stmt *query)
query, 11);
key->roaming = sqlite3_column_int(
query, 12);
+ key->imsi_hash = strdup((char *)sqlite3_column_text(
+ query, 15));
+ key->ground = sqlite3_column_int(query, 16);
value->send_quota = sqlite3_column_int64(
query, 1);
@@ -168,14 +181,21 @@ static void obtain_and_keep_quotas(sqlite3_stmt *query)
value->quota_id = sqlite3_column_int(
query, 14);
+ _D("populate quota tree:");
+ _D("app_id: %s", key->app_id);
+ _D("iftype: %d", key->iftype);
+ _D("roaming: %d", key->roaming);
+ _D("imsi_hash: %s", key->imsi_hash);
+ _D("quota_id: %d", value->quota_id);
+ _D("ground: %d", key->ground);
g_tree_insert(quotas, key, value);
}
} while (rc == SQLITE_ROW);
- return;
+ return RESOURCED_ERROR_NONE;
free_value:
- if (value)
- g_free(value);
+ g_free(value);
+ return ret;
}
static gint compare_quota_key(gconstpointer a, gconstpointer b,
@@ -183,18 +203,56 @@ static gint compare_quota_key(gconstpointer a, gconstpointer b,
{
const struct quota_key *key1 = a;
const struct quota_key *key2 = b;
- /* the first part of the key is equal compare second */
- return strcmp(key1->app_id, key2->app_id) ||
- key1->iftype - key2->iftype ||
- key1->roaming - key2->roaming;
+ int ret = 0;
+
+ /* the main use case of setting it's different quotas
+ * per sim, and only afterward by appid */
+
+ if (key1->imsi_hash && key2->imsi_hash)
+ ret = strcmp(key1->imsi_hash, key2->imsi_hash);
+ else if (!key1->imsi_hash || !key2->imsi_hash) /* in case of one empty another not */
+ ret = key1->imsi_hash - key2->imsi_hash;
+
+ if (ret) {
+ _D("quotas different by imsi");
+ return ret;
+ }
+
+ if (key1->app_id && key2->app_id)
+ ret = strcmp(key1->app_id, key2->app_id);
+ if (ret) {
+ _D("quotas different by app_id");
+ return ret;
+ }
+
+ ret = key1->iftype - key2->iftype;
+ if (ret) {
+ _D("quotas different by iftype");
+ return ret;
+ }
+ ret = key1->ground - key2->ground;
+ if (ret) {
+ _D("quotas different by ground");
+ return ret;
+ }
+ return key1->roaming - key2->roaming;
}
-#define quota_key_destructor g_free
+static void quota_key_destructor(void *key)
+{
+ struct quota_key *qkey = (struct quota_key *)key;
+ if (qkey->app_id)
+ free((char *)qkey->app_id);
+ if (qkey->imsi_hash)
+ free((char *)qkey->imsi_hash);
+ g_free(key);
+}
#define quota_destructor g_free
-static void _clear_effective_quota(const char *app_id,
+void clear_effective_quota(const char *app_id,
const resourced_iface_type iftype,
- const resourced_roaming_type roaming)
+ const resourced_roaming_type roaming,
+ const char *imsi_hash)
{
if (sqlite3_bind_text(clear_effective_stmt, 1, app_id, -1,
SQLITE_TRANSIENT) != SQLITE_OK) {
@@ -217,6 +275,13 @@ static void _clear_effective_quota(const char *app_id,
return;
}
+ if (sqlite3_bind_text(clear_effective_stmt, 4, imsi_hash, -1, SQLITE_TRANSIENT)
+ != SQLITE_OK) {
+ _E("Can not bind subscriber_id:%s for preparing statement:%s",
+ imsi_hash, sqlite3_errmsg(resourced_get_database()));
+ return;
+ }
+
if (sqlite3_step(clear_effective_stmt) != SQLITE_DONE)
_E("Failed to clear effective quotas %s",
sqlite3_errmsg(resourced_get_database()));
@@ -269,7 +334,7 @@ static data_usage_quota_period_t _define_period(const int time_period, int *quan
}
-static time_t _get_finish_time(const time_t start_time, const int time_period)
+static time_t get_finish_time(const time_t start_time, const int time_period)
{
int quantity = 0;
struct tm *new_start = gmtime((const time_t *)&start_time);
@@ -299,6 +364,8 @@ struct data_usage_context {
int64_t sent_used_quota;
int64_t rcv_used_quota;
resourced_roaming_type roaming;
+ const char *imsi;
+ resourced_state_t ground;
};
static resourced_cb_ret data_usage_details_cb(const data_usage_info *info,
@@ -307,14 +374,25 @@ static resourced_cb_ret data_usage_details_cb(const data_usage_info *info,
struct data_usage_context *context =
(struct data_usage_context *)user_data;
- if (!context ||
- (context->roaming != RESOURCED_ROAMING_UNKNOWN &&
- context->roaming != info->roaming))
+ ret_value_msg_if(!context, RESOURCED_CONTINUE,
+ "Invalid cb data!");
+
+ if (context->roaming != info->roaming)
+ return RESOURCED_CONTINUE;
+
+ if (!CHECK_BIT(context->ground, info->ground))
return RESOURCED_CONTINUE;
- context->sent_used_quota = info->foreground.cnt.incoming_bytes;
- context->rcv_used_quota = info->foreground.cnt.outgoing_bytes;
- return RESOURCED_CANCEL; /* only one entry allowed */
+ /* if imsi is not specified, e.g. for WiFi
+ * need additional check*/
+ if (info->imsi && context->imsi && strcmp(context->imsi, info->imsi))
+ return RESOURCED_CONTINUE;
+
+ context->sent_used_quota += info->cnt.outgoing_bytes;
+ context->rcv_used_quota += info->cnt.incoming_bytes;
+ /* calculate all traffic, several iteration could be
+ * needed when end user request quota for unknown roaming */
+ return RESOURCED_CONTINUE;
}
static void _record_quota(const struct quota_key *key,
@@ -387,25 +465,40 @@ static void _record_quota(const struct quota_key *key,
return;
}
+ if (sqlite3_bind_text(insert_stmt, 9, key->imsi_hash, -1,
+ SQLITE_STATIC)
+ != SQLITE_OK) {
+ _E("Can not bind subscriber_id:%s for preparing statement",
+ key->imsi_hash);
+ return;
+ }
+
if (sqlite3_step(insert_stmt) != SQLITE_DONE)
_D("Failed to record quotas %s", sqlite3_errmsg(resourced_get_database()));
sqlite3_reset(insert_stmt);
}
-static void _set_effective_quota(const char *app_id,
+static time_t rule_start_time(time_t start_time,
+ time_t cur_time,
+ time_t time_interval)
+{
+ if (cur_time - start_time > time_interval)
+ return cur_time - (cur_time - start_time) % time_interval;
+ return start_time;
+}
+
+static void set_effective_quota(const char *app_id,
const resourced_iface_type iftype, const time_t start_time,
const int time_period,
- const resourced_roaming_type roaming)
+ const resourced_roaming_type roaming,
+ const char *imsi_hash,
+ const resourced_state_t ground,
+ struct quota *app_quota)
{
data_usage_selection_rule rule = {0,};
struct data_usage_context out_context = {0,};
- struct quota_key key_quota = {
- .app_id = app_id,
- .iftype = iftype,
- .roaming = roaming,
- };
- struct quota app_quota = {0,};
const time_t cur_time = time(0);
+ app_id = !strcmp(app_id, RESOURCED_ALL_APP) ? 0: app_id;
if (cur_time < start_time) {
_D("No need to update effective quota!");
@@ -413,7 +506,13 @@ static void _set_effective_quota(const char *app_id,
}
out_context.roaming = roaming;
- rule.from = start_time;
+ out_context.imsi = imsi_hash;
+ out_context.ground = ground;
+ /* user could specify start_time far ago in the past, and
+ * we will recalculate since that time, it's not good,
+ * especially if time_period is smaller then
+ * current_time - start_time */
+ rule.from = rule_start_time(start_time, cur_time, time_period);
rule.to = cur_time;
rule.iftype = iftype;
@@ -423,58 +522,161 @@ static void _set_effective_quota(const char *app_id,
return;
}
- _SD("Get counted traffic for appid:%s, per"
- "%s, incoming:%d, outgoing:%d", app_id, ctime(&start_time),
- out_context.rcv_used_quota, out_context.sent_used_quota);
-
- app_quota.sent_used_quota = out_context.sent_used_quota;
- app_quota.rcv_used_quota = out_context.rcv_used_quota;
- app_quota.real_start = start_time;
- app_quota.real_finish = _get_finish_time(start_time, time_period);
- app_quota.state = RESOURCED_QUOTA_APPLIED;
- _record_quota(&key_quota, &app_quota);
+ _SD("Get counted traffic for appid:%s, per %s "\
+ "time interval %d, incoming:%" PRId64 ", outgoing:%" PRId64 "", app_id,
+ ctime(&rule.from), time_period, out_context.rcv_used_quota,
+ out_context.sent_used_quota);
+
+ app_quota->sent_used_quota = out_context.sent_used_quota;
+ app_quota->rcv_used_quota = out_context.rcv_used_quota;
+ app_quota->real_start = rule.from; /* otherwise we could get
+ real_finish in the past */
+ app_quota->real_finish = get_finish_time(app_quota->real_start,
+ time_period);
}
-void update_quota_state(const char *app_id,
- const resourced_iface_type iftype,
- const time_t start_time,
- const int time_period,
- const resourced_roaming_type roaming)
+static struct quota *find_quota_in_tree(const char *app_id,
+ const resourced_iface_type iftype, const resourced_roaming_type roaming,
+ const char *imsi, const resourced_state_t ground)
{
struct quota_key key;
+ key.app_id = app_id;
+ key.iftype = iftype;
+ key.roaming = roaming;
+ key.imsi_hash = imsi;
+ key.ground = ground;
+ return (struct quota *)g_tree_lookup(quotas, &key);
+}
+
+bool check_quota_applied(const char *app_id, const resourced_iface_type iftype,
+ const resourced_roaming_type roaming, const char *imsi,
+ const resourced_state_t ground, int *quota_id)
+{
+ struct quota *tree_value = find_quota_in_tree(app_id, iftype, roaming,
+ imsi, ground);
+
+ if (!tree_value)
+ return false;
+ *quota_id = tree_value->quota_id;
+ return tree_value->state == RESOURCED_QUOTA_APPLIED;
+}
+
+void update_quota_state(const char *app_id, const int quota_id,
+ struct serialization_quota *ser_quota)
+{
struct quota *tree_value;
+ struct quota_key *insert_key;
if (!app_id) {
_SE("app_id must be not NULL");
return;
}
- key.app_id = app_id;
- key.iftype = iftype;
- key.roaming = roaming;
- tree_value = (struct quota *)g_tree_search(quotas,
- (GCompareFunc)compare_quota_key, &key);
+ tree_value = find_quota_in_tree(app_id, ser_quota->iftype,
+ ser_quota->roaming_type,
+ ser_quota->imsi_hash, ser_quota->quota_type);
+ if (!check_event_in_current_modem(ser_quota->imsi_hash,
+ ser_quota->iftype))
+ check_and_clear_all_noti();
if (tree_value && tree_value->state == RESOURCED_QUOTA_APPLIED) {
- _SD("Removing quota and restriction for %s,%d", app_id, iftype);
+ _SD("Removing quota and restriction for %s,%d, %s", app_id,
+ ser_quota->iftype, ser_quota->imsi_hash);
/* Restrictions can't be separated */
- remove_restriction_local(app_id, iftype);
- g_tree_remove(quotas, (gconstpointer*)(&key));
- _clear_effective_quota(app_id, iftype, roaming);
+ if (remove_restriction_local(app_id, ser_quota->iftype,
+ tree_value->quota_id, ser_quota->imsi_hash,
+ ser_quota->quota_type) == RESOURCED_ERROR_NONE)
+ tree_value->state = RESOURCED_QUOTA_REVERTED;
+ else
+ _D("failed to revert quota %d", tree_value->quota_id);
+
+ clear_effective_quota(app_id, ser_quota->iftype,
+ ser_quota->roaming_type, ser_quota->imsi_hash);
+ } else if (!tree_value) {
+ insert_key = malloc(sizeof(struct quota_key));
+ ret_msg_if (!insert_key, "not enough memory");
+ memset(insert_key, 0, sizeof(struct quota_key));
+ tree_value = (struct quota *)malloc(sizeof(struct quota));
+ if (!tree_value) {
+ _E("not enough memory");
+ goto release_quota_key;
+ }
+
+ memset(tree_value, 0, sizeof(struct quota));
+ /* app_id was allocated by dbus, and it will be freed
+ * when dbus request is gone */
+ insert_key->app_id = strdup(app_id);
+ if (!insert_key->app_id) {
+ _E("not enough memory");
+ goto release_quota_value;
+ }
- if (start_time && time_period)
- _set_effective_quota(app_id, iftype, start_time,
- time_period, roaming);
- } else
- _SD("There is no quota %s,%d in tree", app_id, iftype);
+ insert_key->imsi_hash = strdup(ser_quota->imsi_hash);
+ if (!insert_key->imsi_hash) {
+ _E("not enough memory");
+ goto release_app_id;
+ }
+ insert_key->iftype = ser_quota->iftype;
+ insert_key->roaming = ser_quota->roaming_type;
+ _SD("There is no quota %s,%d in tree", app_id,
+ ser_quota->iftype);
+ insert_key->ground = ser_quota->quota_type;
+ g_tree_insert(quotas, insert_key, tree_value);
+ }
+
+ /* we already stored quota, so _set_effective_quota, stores
+ * effective quota in db with new calculated value for exceeded
+ * trafifc */
+ tree_value->send_quota = ser_quota->snd_quota;
+ tree_value->rcv_quota = ser_quota->rcv_quota;
+ /*
+ * in case of APPLIED/REVERTED quota used traffic need to clear
+ * it will be recalculated in set_effective_quota, due start
+ * time could be changed,
+ * also data_usage_details_foreach could fail, or user
+ * could not specify start_time and time_period
+ */
+ tree_value->sent_used_quota = 0;
+ tree_value->rcv_used_quota = 0;
+ tree_value->snd_warning_threshold = ser_quota->snd_warning_threshold;
+ tree_value->rcv_warning_threshold = ser_quota->rcv_warning_threshold;
+ /* link with restriction */
+ tree_value->quota_id = quota_id;
+ set_effective_quota(app_id, ser_quota->iftype, ser_quota->start_time,
+ ser_quota->time_period, ser_quota->roaming_type,
+ ser_quota->imsi_hash, ser_quota->quota_type,
+ tree_value);
+
+ return;
+
+release_app_id:
+ free((char *)insert_key->app_id);
+release_quota_value:
+ free(tree_value);
+release_quota_key:
+ free(insert_key);
+}
+
+void remove_quota_from_counting(const char *app_id, const resourced_iface_type iftype,
+ const resourced_roaming_type roaming,
+ const char *imsi_hash)
+{
+ struct quota_key key;
+ ret_msg_if(!app_id,"app_id must be not NULL");
+
+ key.app_id = app_id;
+ key.iftype = iftype;
+ key.roaming = roaming;
+ key.imsi_hash = strdup(imsi_hash);
+
+ g_tree_remove(quotas, (gconstpointer*)(&key));
}
+
static resourced_ret_c _init_quotas(void)
{
- execute_once {
- quotas = g_tree_new_full(compare_quota_key, NULL,
+ quotas = g_tree_new_full(compare_quota_key, NULL,
quota_key_destructor, quota_destructor);
- }
if (!resourced_get_database())
return RESOURCED_ERROR_DB_FAILED;
@@ -521,34 +723,29 @@ handle_error:
/**
* Update quotas tree, where app_id will the key
*/
-static resourced_ret_c _update_quotas(void)
+static resourced_ret_c load_quotas(void)
{
const resourced_ret_c ret = _init_quotas();
- if (ret != RESOURCED_ERROR_NONE) {
- _E("Failed to init quotas");
- return ret;
- }
-
- obtain_and_keep_quotas(select_stmt);
- return RESOURCED_ERROR_NONE;
+ ret_value_msg_if (ret != RESOURCED_ERROR_NONE, ret, "Failed to init quotas");
+ return obtain_and_keep_quotas(select_stmt);
}
static const int64_t quota_gap_value[RESOURCED_IFACE_ALL] = {
- 5000, /* ~4.5MB UNKNOWN */
- 5000, /* ~3MB RESOURCED_IFACE_DATACALL */
+ 400000, /* ~4.5MB UNKNOWN */
+ 400000, /* ~3MB RESOURCED_IFACE_DATACALL */
6000000, /* ~6MB RESOURCED_IFACE_WIFI */
5000000, /* ~100MB RESOURCED_IFACE_WIRED */
6000000, /* ~6MB RESOURCED_IFACE_BLUETOOTH */
};
static const int64_t quota_datacall_gap_value[RESOURCED_PROTOCOL_MAX_ELEM] = {
- 5000, /* RESOURCED_PROTOCOL_NONE */
- 5000, /* RESOURCED_PROTOCOL_DATACALL_NOSVC */
- 5000, /* RESOURCED_PROTOCOL_DATACALL_EMERGENCY */
- 5000, /* RESOURCED_PROTOCOL_DATACALL_SEARCH */
- 5000, /* RESOURCED_PROTOCOL_DATACALL_2G */
- 5000, /* RESOURCED_PROTOCOL_DATACALL_2_5G #GPRS 40 kbit/s in practice */
- 18750, /* RESOURCED_PROTOCOL_DATACALL_2_5G_EDGE 150 kbit/s in practice */
+ 400000, /* RESOURCED_PROTOCOL_NONE */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_NOSVC */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_EMERGENCY */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_SEARCH */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_2G */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_2_5G #GPRS 40 kbit/s in practice */
+ 400000, /* RESOURCED_PROTOCOL_DATACALL_2_5G_EDGE 150 kbit/s in practice */
400000, /* RESOURCED_PROTOCOL_DATACALL_3G, 7Mb/s on QC device */
475000, /* RESOURCED_PROTOCOL_DATACALL_HSDPA */
5000000,/* RESOURCED_PROTOCOL_DATACALL_LTE */
@@ -560,7 +757,8 @@ static const int64_t quota_datacall_gap_value[RESOURCED_PROTOCOL_MAX_ELEM] = {
static int64_t _get_quota_gap(const resourced_iface_type iftype)
{
- const resourced_hw_net_protocol_type proto = get_hw_net_protocol_type(iftype);
+ const resourced_hw_net_protocol_type proto = get_current_protocol(iftype);
+ _D("proto: %d, iftype: %d", proto, iftype);
if (proto != RESOURCED_PROTOCOL_NONE)
return quota_datacall_gap_value[proto];
@@ -572,7 +770,7 @@ static int64_t _get_quota_gap(const resourced_iface_type iftype)
return quota_gap_value[RESOURCED_IFACE_UNKNOWN];
}
-int _is_under_restriction(const int64_t send_delta,
+static int check_restriction_needed(const int64_t send_delta,
const int64_t rcv_delta,
const resourced_iface_type iftype,
int update_period)
@@ -587,21 +785,11 @@ int _is_under_restriction(const int64_t send_delta,
rcv_delta <= quota_gap;
}
-inline void _check_warning_threshold(const int64_t send_delta, const int64_t rcv_delta,
- struct quota *app_quota, const char *appid)
+inline static int get_warning_limit(int64_t delta, int64_t limit, int threshold)
{
- ret_msg_if(!app_quota, "Please provide valid pointer");
+ if (delta < threshold)
+ return 0; /* send warning immediately */
- if (send_delta <= app_quota->snd_warning_threshold ||
- rcv_delta <= app_quota->rcv_warning_threshold) {
- app_quota->snd_warning_threshold = 0;
- app_quota->rcv_warning_threshold = 0;
- send_restriction_warn_notification(appid);
- }
-}
-
-inline static int _get_warning_limit(int64_t limit, int threshold)
-{
if (limit < threshold) {
_E("Warning threshold is greater than limit!");
return WARNING_THRESHOLD_DEFAULT; /* 0 means kernel will
@@ -619,72 +807,146 @@ static int cast_restriction_limit(int64_t delta)
return delta;
}
+static bool skip_quota(struct quota_key *key_quota, struct quota *app_quota,
+ const int64_t send_delta, const int64_t rcv_delta)
+{
+ char *imsi_hash;
+ /* do not check already applied quota*/
+ if (app_quota->state == RESOURCED_QUOTA_APPLIED) {
+ _D("already applied");
+ return true;
+ }
+
+ if (!strcmp(key_quota->app_id, TETHERING_APP_NAME) &&
+ (send_delta > 0 || rcv_delta > 0)) {
+ _D("tethering");
+ /* in the case of tethering we send
+ restriction only that must apply now */
+ return true;
+ }
+
+ if (key_quota->iftype == RESOURCED_IFACE_DATACALL) {
+ /* TODO it could get_current_modem_imsi_hash, and
+ * it could be faster */
+ imsi_hash = get_imsi_hash(get_current_modem_imsi());
+ /* in redwood imsi could be null due absent telephony
+ * response */
+ if (!check_imsi_hash(key_quota->imsi_hash, imsi_hash)) {
+ _D("imsi different");
+ return true;
+ }
+ }
+ /* TODO the same check for current iftype, without it
+ * WiFi quota and datacall quota couldn't coexit */
+ return false;
+}
+
static gboolean check_and_apply_node(gpointer key,
gpointer value, gpointer user_data)
{
struct quota *app_quota = value;
struct quota_key *key_quota = key;
- int64_t send_delta, rcv_delta;
- struct daemon_opts *opts = (struct daemon_opts *)user_data;
+ struct counter_arg *carg = (struct counter_arg *)user_data;
resourced_net_restrictions rst = { RESOURCED_STATE_UNKNOWN,
- RESOURCED_IFACE_UNKNOWN };
+ RESOURCED_IFACE_UNKNOWN,};
+ int64_t send_delta = app_quota->send_quota - app_quota->sent_used_quota;
+ int64_t rcv_delta = app_quota->rcv_quota - app_quota->rcv_used_quota;
+ struct daemon_opts *opts;
- /* do not check already applied quota*/
- if (app_quota->state == RESOURCED_QUOTA_APPLIED)
- return FALSE;
+ ret_value_msg_if(!carg, FALSE, "Please provide valid carg argument!");
+
+ opts = carg->opts;
- send_delta = app_quota->send_quota - app_quota->sent_used_quota;
- rcv_delta = app_quota->rcv_quota - app_quota->rcv_used_quota;
+ if (skip_quota(key_quota, app_quota, send_delta, rcv_delta)) {
+ _D("no need to apply quota");
+ return FALSE;
+ }
- if (app_quota->send_quota <= 0 || app_quota->rcv_quota <= 0)
- send_restriction_notification(key_quota->app_id);
- else
- _check_warning_threshold(send_delta, rcv_delta, app_quota,
- key_quota->app_id);
+ _D("quota rcv: %" PRId64 ", send: %" PRId64 "", app_quota->rcv_quota,
+ app_quota->send_quota);
+ _D("delta rcv: %" PRId64 ", send: %" PRId64 "", rcv_delta, send_delta);
- if (_is_under_restriction(send_delta, rcv_delta, key_quota->iftype,
+ /* gap guard part, block immediately if send/rcv_delta is less or
+ * equal zero */
+ if (check_restriction_needed(send_delta, rcv_delta, key_quota->iftype,
opts->update_period) &&
(key_quota->roaming == RESOURCED_ROAMING_UNKNOWN ||
- key_quota->roaming == get_roaming())) {
- if (!strcmp(key_quota->app_id, TETHERING_APP_NAME) &&
- (send_delta > 0 || rcv_delta > 0))
- /* in the case of tethering we send
- restriction only that must apply now */
- return FALSE;
+ key_quota->roaming == get_current_roaming())) {
+ data_usage_quota du_quota = {0}; /* use both for
+ warning/restriction noti */
+ rst.rs_type = key_quota->ground;
rst.send_limit = cast_restriction_limit(send_delta);
rst.rcv_limit = cast_restriction_limit(rcv_delta);
- rst.snd_warning_limit = _get_warning_limit(
- rst.send_limit, app_quota->snd_warning_threshold);
- rst.rcv_warning_limit = _get_warning_limit(
- rst.rcv_limit, app_quota->rcv_warning_threshold);
+ rst.snd_warning_limit = get_warning_limit(send_delta,
+ rst.send_limit, app_quota->snd_warning_threshold);
+ rst.rcv_warning_limit = get_warning_limit(rcv_delta,
+ rst.rcv_limit, app_quota->rcv_warning_threshold);
- _SD("Applying quota for %s, iftype %d", key_quota->app_id,
- key_quota->iftype);
+ _SD("Applying gap quota for %s, iftype %d, ground", key_quota->app_id,
+ key_quota->iftype, key_quota->ground);
rst.iftype = key_quota->iftype;
-
+ rst.ifname = get_iftype_name(rst.iftype);
+ rst.roaming = key_quota->roaming;
+
+ /*
+ * client request quota for background application or
+ * applications, lets create here background cgroup,
+ * we will put later processes in it
+ */
+ if (key_quota->ground == RESOURCED_STATE_BACKGROUND)
+ create_net_background_cgroup(carg);
+
+ /* we already checked in check_restriction_needed
+ * is it current imsi or not,
+ * just do not skip kernel op */
if (proc_keep_restriction(key_quota->app_id,
- app_quota->quota_id, &rst,
- RST_SET) == RESOURCED_ERROR_NONE) {
- app_quota->state = RESOURCED_QUOTA_APPLIED;
- _D("Restriction was applied successfully.");
+ app_quota->quota_id, &rst,
+ RST_SET, false) != RESOURCED_ERROR_NONE) {
+ _E("Failed to keep restriction!");
+ return FALSE;
}
+
+ du_quota.snd_quota = app_quota->send_quota;
+ du_quota.rcv_quota = app_quota->rcv_quota;
+ du_quota.quota_type = key_quota->ground;
+
+ /*
+ * in case of !rst.send_limit and !rst.rcv_limit
+ * restriction will come from fill_restriction nfacct handler
+ * */
+ if (/*!rst.send_limit || */ !rst.rcv_limit)
+ send_restriction_notification(key_quota->app_id, &du_quota);
+ else if (/*!rst.snd_warning_limit ||*/!rst.rcv_warning_limit)
+ send_restriction_warn_notification(key_quota->app_id, &du_quota);
+
+ app_quota->state = RESOURCED_QUOTA_APPLIED;
+ _D("Restriction was applied successfully.");
+
}
return FALSE; /* continue iteration */
}
-static void check_and_apply_quota(volatile struct daemon_opts *opts)
+static void check_and_apply_quota(struct counter_arg *carg)
{
- g_tree_foreach(quotas, check_and_apply_node, (void *)opts);
+ g_tree_foreach(quotas, check_and_apply_node, (void *)carg);
}
struct update_all_arg
{
resourced_iface_type iftype;
+ char *imsi_hash;
struct application_stat *app_stat;
};
+static inline bool check_imsi_hash(const char *hash_a, const char *hash_b)
+{
+ if (hash_a && hash_b)
+ return !strcmp(hash_a, hash_b);
+ return hash_a == hash_b; /* both null */
+}
+
static gboolean update_pseudo_app_entry(gpointer key,
gpointer value, gpointer user_data)
{
@@ -692,25 +954,38 @@ static gboolean update_pseudo_app_entry(gpointer key,
update_all_arg *)user_data;
const struct quota_key *qkey = (const struct
quota_key *)key;
+ struct quota *total_quota = (struct quota *)value;
+
+ if (time(0) < total_quota->start_time) {
+ _D("No need to update effective quota!");
+ return FALSE;
+ }
+
+ _D("app id %s", qkey->app_id);
+ _D("app ground %d", qkey->ground);
+ _D("app stat app_id %s", arg->app_stat->application_id);
+ _D("app stat ground %d", arg->app_stat->ground);
/* handle case for network interfaces*/
if ((!strcmp(qkey->app_id, RESOURCED_ALL_APP) &&
(qkey->iftype == RESOURCED_IFACE_UNKNOWN ||
qkey->iftype == RESOURCED_IFACE_ALL ||
qkey->iftype == arg->iftype) &&
+ (check_imsi_hash(qkey->imsi_hash, arg->imsi_hash)) &&
(qkey->roaming == RESOURCED_ROAMING_UNKNOWN ||
- qkey->roaming == arg->app_stat->is_roaming)) ||
- !strcmp(qkey->app_id, TETHERING_APP_NAME)) {
- struct quota *total_quota = (struct quota *)value;
+ qkey->roaming == arg->app_stat->is_roaming) &&
+ CHECK_BIT(qkey->ground, arg->app_stat->ground)) ||
+ !strcmp(qkey->app_id, TETHERING_APP_NAME))
+ {
/* update it */
total_quota->sent_used_quota += arg->app_stat->delta_snd;
total_quota->rcv_used_quota += arg->app_stat->delta_rcv;
arg->app_stat->delta_snd = 0;
arg->app_stat->delta_rcv = 0;
- _D("update total_quota tx:%"PRId64";rx:%"PRId64" iftype %d ifindex %d\n",
+ _D("update total_quota tx:%"PRId64";rx:%"PRId64" iftype %d \n",
total_quota->sent_used_quota, total_quota->rcv_used_quota,
- arg->iftype, arg->app_stat->ifindex);
-
+ arg->iftype);
+ _D("app id %s", qkey->app_id);
}
return FALSE;
@@ -757,6 +1032,8 @@ static gboolean update_each_quota(gpointer key, gpointer value,
.app_stat = app_stat
};
struct quota_key qkey;
+ arg.imsi_hash = app_key->iftype == RESOURCED_IFACE_DATACALL ?
+ get_imsi_hash(app_key->imsi) : "";
/* We should handle cases of RESOURCED_ALL_APP or TETHERING_APP_NAME
in separate way due it's not comming with statistics from kernel */
@@ -768,6 +1045,8 @@ static gboolean update_each_quota(gpointer key, gpointer value,
qkey.app_id = app_stat->application_id;
qkey.iftype = app_key->iftype;
qkey.roaming = app_stat->is_roaming;
+ /* TODO following code could be a function */
+ qkey.imsi_hash = app_key->iftype == RESOURCED_IFACE_DATACALL ? get_imsi_hash(app_key->imsi): "";
update_traffic_quota(&qkey, &app_stat->delta_snd,
&app_stat->delta_rcv);
return FALSE;
@@ -789,7 +1068,7 @@ static void calculate_finish_time(struct quota *app_quota)
if (!app_quota->real_start)
app_quota->real_start = time(0);
- app_quota->real_finish = _get_finish_time(app_quota->real_start,
+ app_quota->real_finish = get_finish_time(app_quota->real_start,
app_quota->time_period);
}
@@ -822,7 +1101,8 @@ static void drop_restriction(const struct quota_key *qkey, struct quota *app_quo
_SD("Removing restriction of quota for %s,%d", qkey->app_id,
qkey->iftype);
- if (remove_restriction_local(qkey->app_id, qkey->iftype)
+ if (remove_restriction_local(qkey->app_id, qkey->iftype,
+ app_quota->quota_id, qkey->imsi_hash, qkey->ground)
== RESOURCED_ERROR_NONE)
app_quota->state = RESOURCED_QUOTA_REVERTED;
}
@@ -868,31 +1148,108 @@ static void finalize_statement(sqlite3_stmt **stmt)
}
}
-resourced_ret_c process_quota(struct application_stat_tree *apps,
- volatile struct daemon_opts *opts)
+resourced_ret_c process_quota(struct counter_arg *carg)
{
- /* For first initialization */
- static int quota_updated;
+ ret_value_msg_if(!carg, RESOURCED_ERROR_INVALID_PARAMETER,
+ "Please provide carg!");
- if (opts && opts->is_update_quota) {
- const int error = _update_quotas();
- if (error)
- return error;
- quota_updated = 1;
+ execute_once {
+ const resourced_ret_c ret = load_quotas();
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "Failed to load quotas!");
}
- actualize_quota_table(apps);
+ actualize_quota_table(carg->result);
- check_and_apply_quota(opts);
+ check_and_apply_quota(carg);
- /* finilize state */
- if (opts && opts->is_update_quota && quota_updated) {
- opts->is_update_quota = 0;
- quota_updated = 0;
- }
return RESOURCED_ERROR_NONE;
}
+struct quota_search_context {
+ int quota_id;
+ struct quota *quota;
+ struct quota_key *key;
+};
+
+static gboolean search_quota_cb(gpointer key, gpointer value, gpointer data)
+{
+ struct quota_search_context *ctx = (struct quota_search_context *)data;
+ struct quota *quota = (struct quota *)value;
+ /**
+ * quota id is uniqe, but not in key, because isn't used in
+ * checking quota
+ */
+ if (ctx->quota_id == quota->quota_id) {
+ ctx->quota = quota;
+ ctx->key = key;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean search_background_quota_cb(gpointer key, gpointer value, gpointer data)
+{
+ bool *background = (bool *)data;
+ struct quota *quota = (struct quota *)value;
+ struct quota_key *qkey = (struct quota_key *)key;
+ /**
+ * quota id is uniqe, but not in key, because isn't used in
+ * checking quota
+ */
+ if (quota->state == RESOURCED_QUOTA_APPLIED &&
+ qkey->ground == RESOURCED_STATE_BACKGROUND) {
+ *background = true;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+resourced_ret_c get_quota_by_id(const int quota_id, data_usage_quota *du_quota)
+{
+ struct quota_search_context ctx = {.quota_id = quota_id};
+ execute_once {
+ if (!g_tree_nnodes(quotas))
+ load_quotas();
+ }
+ g_tree_foreach(quotas, search_quota_cb, &ctx);
+ if (ctx.key && ctx.quota) {
+ du_quota->snd_quota = ctx.quota->send_quota;
+ du_quota->rcv_quota = ctx.quota->rcv_quota;
+ du_quota->imsi = ctx.key->imsi_hash;
+ du_quota->quota_type = ctx.key->ground;
+ return RESOURCED_ERROR_NONE;
+ }
+ return RESOURCED_ERROR_FAIL;
+}
+
+resourced_ret_c get_quota_by_appid(const char* app_id, const char *imsi_hash,
+ const resourced_iface_type iftype, resourced_roaming_type roaming,
+ data_usage_quota *du_quota, int *quota_id, resourced_state_t ground)
+{
+ struct quota *qt;
+ execute_once {
+ if (!g_tree_nnodes(quotas))
+ load_quotas();
+ }
+
+ qt = find_quota_in_tree(app_id, iftype, roaming, imsi_hash, ground);
+ if (qt) {
+ du_quota->snd_quota = qt->send_quota;
+ du_quota->rcv_quota = qt->rcv_quota;
+ *quota_id = qt->quota_id;
+ return RESOURCED_ERROR_NONE;
+ }
+ return RESOURCED_ERROR_FAIL;
+}
+
+bool get_background_quota(void)
+{
+ bool background = false;
+ g_tree_foreach(quotas, search_background_quota_cb, &background);
+ return background;
+}
+
/**
* Release statement
*/
diff --git a/src/network/datausage-quota.c b/src/network/datausage-quota.c
index 60c09e76..fac0f76f 100644
--- a/src/network/datausage-quota.c
+++ b/src/network/datausage-quota.c
@@ -84,7 +84,7 @@ static resourced_ret_c send_quota_message(const char *interface,
static resourced_ret_c send_create_quota_message(const char *app_id,
const data_usage_quota *quota)
{
- char *params[10];
+ char *params[11];
char snd_quota[MAX_DEC_SIZE(int64_t)], rcv_quota[MAX_DEC_SIZE(int64_t)];
snprintf(snd_quota, sizeof(snd_quota), "%" PRId64 "", quota->snd_quota);
@@ -93,20 +93,21 @@ static resourced_ret_c send_create_quota_message(const char *app_id,
serialize_params(params, ARRAY_SIZE(params), app_id, quota->time_period,
snd_quota, rcv_quota, quota->snd_warning_threshold,
quota->rcv_warning_threshold, quota->quota_type, quota->iftype,
- *quota->start_time, quota->roaming_type);
- return send_quota_message(RESOURCED_NETWORK_CREATE_QUOTA, "sdttdddddd",
+ *quota->start_time, quota->roaming_type, quota->imsi);
+ return send_quota_message(RESOURCED_NETWORK_CREATE_QUOTA, "sdttdddddds",
params);
}
static resourced_ret_c send_remove_quota_message(const char *app_id,
const resourced_iface_type iftype,
- const resourced_roaming_type roaming_type)
+ const resourced_roaming_type roaming_type,
+ const char *imsi, const resourced_state_t ground)
{
- char *params[3];
+ char *params[5];
serialize_params(params, ARRAY_SIZE(params), app_id, iftype,
- roaming_type);
- return send_quota_message(RESOURCED_NETWORK_REMOVE_QUOTA, "sdd",
+ roaming_type, imsi, ground);
+ return send_quota_message(RESOURCED_NETWORK_REMOVE_QUOTA, "sddsd",
params);
}
@@ -125,7 +126,7 @@ API resourced_ret_c remove_datausage_quota(
return RESOURCED_ERROR_INVALID_PARAMETER;
return send_remove_quota_message(rule->app_id, rule->iftype,
- rule->roaming);
+ rule->roaming, rule->imsi ? rule->imsi : "", rule->quota_type);
}
API resourced_ret_c remove_datausage_quota_by_iftype(
@@ -188,7 +189,14 @@ API resourced_ret_c set_datausage_quota(const char *app_id,
_SD("quota.rcv_quota = %lld", quota->rcv_quota);
_SD("quota.quota_type = %d", quota->quota_type);
_SD("quota.iftype = %d", quota->iftype);
+ _SD("quota->imsi = %s", quota->imsi);
+ _SD("quota->roaming_type = %d", quota->roaming_type);
+ _SD("quota->snd_warning_threshold = %d", quota->snd_warning_threshold);
+ _SD("quota->rcv_warning_threshold = %d", quota->rcv_warning_threshold);
_SD("===============================");
+ /* replace imsi to empty string if NULL was given*/
+ if (!quota_to_send.imsi)
+ quota_to_send.imsi = "";
return send_create_quota_message(app_id, &quota_to_send);
}
diff --git a/src/network/datausage-vconf-callbacks.c b/src/network/datausage-vconf-callbacks.c
index ae9098a4..9ec94e19 100644
--- a/src/network/datausage-vconf-callbacks.c
+++ b/src/network/datausage-vconf-callbacks.c
@@ -34,6 +34,8 @@
#include "resourced.h"
#include "settings.h"
#include "trace.h"
+#include "telephony.h"
+#include "notification.h"
#include <stdlib.h>
#include <vconf.h>
@@ -87,6 +89,16 @@ static void datausage_timer_change_cb(keynode_t *key, void *data)
options->update_period = val;
}
+static void datausage_sim_change_cb(keynode_t *key, void *data)
+{
+ int val = vconf_keynode_get_int(key);
+
+ _SD("key = %s, value = %d(int)\n",
+ vconf_keynode_get_name(key), val);
+
+ check_and_clear_all_noti();
+}
+
void resourced_add_vconf_datausage_cb(struct counter_arg *carg)
{
_D("Add vconf datausage callbacks\n");
@@ -101,6 +113,9 @@ void resourced_add_vconf_datausage_cb(struct counter_arg *carg)
vconf_notify_key_changed(RESOURCED_DATACALL_LOGGING_PATH,
datacall_logging_change_cb,
(void *)carg->opts);
+ vconf_notify_key_changed(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE,
+ datausage_sim_change_cb,
+ NULL);
}
void resourced_remove_vconf_datausage_cb(void)
@@ -113,4 +128,6 @@ void resourced_remove_vconf_datausage_cb(void)
datausage_timer_change_cb);
vconf_ignore_key_changed(RESOURCED_DATACALL_LOGGING_PATH,
datacall_logging_change_cb);
+ vconf_ignore_key_changed(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE,
+ datausage_sim_change_cb);
}
diff --git a/src/network/datausage-vconf-common.c b/src/network/datausage-vconf-common.c
index 3d914b11..a932d0e3 100644
--- a/src/network/datausage-vconf-common.c
+++ b/src/network/datausage-vconf-common.c
@@ -45,16 +45,6 @@ resourced_ret_c restriction_check_limit_status(int *retval)
return RESOURCED_ERROR_NONE;
}
-resourced_ret_c restriction_read_quota(int *quota)
-{
- if (vconf_get_int(VCONFKEY_SETAPPL_DATA_LIMIT_INT, quota)) {
- _E("vconf_get_int FAIL\n");
- return RESOURCED_ERROR_FAIL;
- };
-
- return RESOURCED_ERROR_NONE;
-}
-
void restriction_set_status(int value)
{
int limit = RESTRICTION_STATE_INIT;
diff --git a/src/network/db-guard.c b/src/network/db-guard.c
new file mode 100644
index 00000000..5ed9b4dc
--- /dev/null
+++ b/src/network/db-guard.c
@@ -0,0 +1,118 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 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 db-guard.c
+ *
+ * @desc This guard procedures are responsible for period db erasing
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <data_usage.h>
+#include <vconf/vconf.h>
+#include <Ecore.h>
+
+#include "config.h"
+#include "counter.h"
+#include "macro.h"
+#include "trace.h"
+
+#define VCONF_KEY_DB_ENTRIES_COUNT "db/private/resourced/network_db_entries"
+#define ENTRY_SIZE 128
+
+/* one hour */
+#define ERASE_TIMER_INTERVAL 3600
+/* 40 days */
+#define ERASE_INTERVAL 3600 * 24 * 40
+/* 50 Mb */
+#define DB_SIZE_THRESHOLD 1048576 * 50
+
+static int db_entries;
+
+resourced_ret_c reset_data_usage_first_n_entries(int num);
+
+void change_db_entries_num_num(int num)
+{
+ db_entries += num;
+ if (vconf_set_int(VCONF_KEY_DB_ENTRIES_COUNT, db_entries))
+ _E("Failed to set new db entries number");
+}
+
+static void check_erase_db_oversize(void)
+{
+ struct stat db_stat = {0};
+ int del_entry = 0;
+
+ ret_msg_if(stat(DATABASE_FULL_PATH, &db_stat),
+ "Failed to get statistics for %s errno %d",
+ DATABASE_FULL_PATH, errno);
+ if (db_stat.st_size < DB_SIZE_THRESHOLD) {
+ _D("Db truncation isn't required!");
+ return;
+ }
+ /* get approximate number of entries for removing */
+ del_entry = (db_stat.st_size - DB_SIZE_THRESHOLD) / ENTRY_SIZE;
+ ret_msg_if(reset_data_usage_first_n_entries(del_entry),
+ "Failed to remove first %d entries", del_entry);
+ change_db_entries_num_num(-del_entry);
+}
+
+static void erase_old_entries(void)
+{
+ data_usage_reset_rule rule = {
+ .iftype = RESOURCED_IFACE_LAST_ELEM,
+ };
+ resourced_tm_interval interval;
+ time_t until = time(0);
+ until -= ERASE_INTERVAL;
+
+ interval.from = 0;
+ interval.to = until;
+ rule.interval = &interval;
+ _D("Reset datausage statistics till %s", asctime(localtime(&until)));
+ ret_msg_if(reset_data_usage(&rule),
+ "Failed to reset statistics");
+}
+
+static Eina_Bool erase_func_cb(void *user_data)
+{
+ check_erase_db_oversize();
+ erase_old_entries();
+ return ECORE_CALLBACK_RENEW;
+}
+
+resourced_ret_c resourced_init_db_guard(struct counter_arg *carg)
+{
+ carg->erase_timer = ecore_timer_add(ERASE_TIMER_INTERVAL,
+ erase_func_cb, carg);
+ ret_value_msg_if(carg->erase_timer == NULL, RESOURCED_ERROR_FAIL,
+ "Failed to create timer");
+ ret_value_msg_if(vconf_get_int(VCONF_KEY_DB_ENTRIES_COUNT, &db_entries),
+ RESOURCED_ERROR_FAIL, "Failed to get vconf %s value!",
+ VCONF_KEY_DB_ENTRIES_COUNT);
+ return RESOURCED_ERROR_NONE;
+}
+
diff --git a/src/network/foreach.c b/src/network/foreach.c
index 0afb3538..e5d49593 100644
--- a/src/network/foreach.c
+++ b/src/network/foreach.c
@@ -35,70 +35,97 @@
#define DATA_USAGE_FOR_PERIOD "select binpath, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, " \
- "sum(sent) as sent from statistics where time_stamp between ? and ? " \
- "group by binpath, is_roaming order by received desc"
+ "sum(sent) as sent, imsi, ground from statistics " \
+ "where time_stamp between ? and ? " \
+ "group by binpath, is_roaming, imsi order by received desc"
#define DATA_USAGE_FOR_PERIOD_IFACE "select binpath, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, " \
- "sum(sent) as sent from statistics where time_stamp between ? and ? " \
- "and iftype=? group by binpath, is_roaming order by received desc"
+ "sum(sent) as sent, imsi, ground from statistics " \
+ "where time_stamp between ? and ? " \
+ "and iftype=? group by binpath, is_roaming, imsi order by received desc"
#define DATA_USAGE_CHUNKS "select binpath, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, " \
- "sum(sent) as sent, time_stamp - time_stamp % ? as time_stamp " \
+ "sum(sent) as sent, time_stamp - time_stamp % ? as time_stamp, imsi, "\
+ "ground " \
"from statistics where time_stamp between ? and ? " \
- "group by binpath, time_stamp order by time_stamp"
+ "group by binpath, time_stamp, imsi order by time_stamp"
#define DATA_USAGE_CHUNKS_IFACE "select binpath, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, " \
- "sum(sent) as sent, time_stamp as start_time, " \
+ "sum(sent) as sent, imsi, ground, " \
"time_stamp - time_stamp % ? as time_stamp " \
"from statistics where time_stamp between ? and ? and iftype=?" \
- "group by binpath, time_stamp order by time_stamp"
+ "group by binpath, time_stamp, imsi order by time_stamp"
#define DATA_USAGE_APP_DETAILS "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname from statistics where time_stamp between ? and ? " \
- "and binpath=? group by binpath, iftype, is_roaming order by iftype"
+ "ifname, imsi, ground from statistics where time_stamp between ? and ? " \
+ "and binpath=? " \
+ "group by binpath, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming " \
+ "order by time_stamp, binpath, iftype, ifname, imsi, " \
+ "hw_net_protocol_type, is_roaming"
#define DATA_USAGE_APP_DETAILS_IFACE "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname from statistics where time_stamp between ? and ? " \
- "and binpath=? and iftype=?"
+ "ifname, imsi, ground from statistics where time_stamp between ? and ? " \
+ "and binpath=? and iftype=?" \
+ "group by hw_net_protocol_type, is_roaming, iftype, ifname, imsi " \
+ "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, "\
+ "ifname, imsi"
#define DATA_USAGE_CHUNKS_APP "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname, time_stamp - time_stamp % ? as time_stamp " \
- "from statistics where time_stamp between ? and ? and binpath = ? " \
- "group by iftype, time_stamp order by time_stamp, iftype"
+ "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \
+ "from statistics " \
+ "group by iftype, ifname, time_stamp, hw_net_protocol_type, is_roaming " \
+ "order by time_stamp, iftype, ifname, hw_net_protocol_type, is_roaming"
#define DATA_USAGE_CHUNKS_APP_IFACE "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname, time_stamp - time_stamp % ? as time_stamp " \
+ "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \
"from statistics where time_stamp between ? and ? and binpath = ? " \
- "and iftype = ? group by time_stamp order by time_stamp"
+ "and iftype = ? " \
+ "group by time_stamp, hw_net_protocol_type, is_roaming, " \
+ "iftype, ifname, imsi " \
+ "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming"
#define DATA_USAGE_TOTAL "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname from statistics where time_stamp between ? and ? " \
- "group by iftype order by iftype, is_roaming"
+ "ifname, imsi, ground from statistics where time_stamp between ? and ? " \
+ "group by iftype, ifname, imsi, hw_net_protocol_type, is_roaming " \
+ "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming"
#define DATA_USAGE_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname from statistics where time_stamp between ? and ? " \
- "and iftype=?"
+ "ifname, imsi, ground from statistics where time_stamp between ? and ? " \
+ "and iftype=? " \
+ "group by hw_net_protocol_type, is_roaming, " \
+ "iftype, ifname, imsi " \
+ "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming"
#define DATA_USAGE_CHUNKS_TOTAL "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname, time_stamp - time_stamp % ? as time_stamp " \
+ "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \
"from statistics where time_stamp between ? and ? " \
- "group by iftype, time_stamp order by time_stamp, iftype"
+ "group by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming " \
+ "order by time_stamp, iftype, ifname, imsi, hw_net_protocol_type, " \
+ "is_roaming"
#define DATA_USAGE_CHUNKS_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \
"is_roaming, sum(received) as received, sum(sent) as sent, " \
- "ifname, time_stamp - time_stamp % ? as time_stamp " \
+ "ifname, imsi, ground, time_stamp - time_stamp % ? as time_stamp " \
"from statistics where time_stamp between ? and ? " \
- "and iftype = ? group by time_stamp order by time_stamp"
+ "and iftype = ? " \
+ "group by time_stamp, hw_net_protocol_type, is_roaming, iftype, ifname, imsi " \
+ "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, " \
+ "ifname, imsi"
static sqlite3_stmt *data_usage_for_period;
static sqlite3_stmt *data_usage_for_period_iface;
@@ -185,7 +212,6 @@ API resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
data_usage_info data;
sqlite3_stmt *stm;
resourced_ret_c result = RESOURCED_ERROR_NONE;
- resourced_counters *cnt = &data.foreground.cnt;
int rc;
int pos = 1;/* running through positions where to
bind parameters in the query */
@@ -198,7 +224,6 @@ API resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
return RESOURCED_ERROR_DB_FAILED;
}
-
memset(&data, 0, sizeof(data));
if (!rule || !info_cb)
@@ -245,10 +270,12 @@ API resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
data.app_id = (char *)sqlite3_column_text(stm, 0);
data.hw_net_protocol_type = sqlite3_column_int(stm, 1);
data.roaming = sqlite3_column_int(stm, 2);
- cnt->incoming_bytes = sqlite3_column_int64(stm, 3);
- cnt->outgoing_bytes = sqlite3_column_int64(stm, 4);
+ data.ground = sqlite3_column_int(stm, 6);
+ data.cnt.incoming_bytes = sqlite3_column_int64(stm, 3);
+ data.cnt.outgoing_bytes = sqlite3_column_int64(stm, 4);
+ data.imsi = (char *)sqlite3_column_text(stm, 5);
if (rule->granularity) {
- interval.from = sqlite3_column_int64(stm, 5);
+ interval.from = sqlite3_column_int64(stm, 7);
interval.to = interval.from + rule->granularity;
}
@@ -286,8 +313,10 @@ static sqlite3_stmt **details_stms[] = {
static sqlite3_stmt *select_statement(const char *app_id,
const data_usage_selection_rule *rule)
{
- return *details_stms[is_iftype_defined(rule->iftype) |
- (app_id ? 0 : 2) | (rule->granularity ? 4 : 0)];
+ const int stm_index = is_iftype_defined(rule->iftype) |
+ (app_id ? 0 : 2) | (rule->granularity ? 4 : 0);
+ _D("stm index %d", stm_index);
+ return *details_stms[stm_index];
}
API resourced_ret_c data_usage_details_foreach(const char *app_id,
@@ -297,7 +326,6 @@ API resourced_ret_c data_usage_details_foreach(const char *app_id,
data_usage_info data;
sqlite3_stmt *stm;
resourced_ret_c result = RESOURCED_ERROR_NONE;
- resourced_counters *cnt = &data.foreground.cnt;
int rc;
int pos = 1;/* running through positions
where to bind parameters in the query */
@@ -360,16 +388,15 @@ API resourced_ret_c data_usage_details_foreach(const char *app_id,
data.iftype = sqlite3_column_int(stm, 0);
data.hw_net_protocol_type = sqlite3_column_int(stm, 1);
data.roaming = sqlite3_column_int(stm, 2);
- cnt->incoming_bytes = sqlite3_column_int64(stm, 3);
- cnt->outgoing_bytes = sqlite3_column_int64(stm, 4);
+ data.cnt.incoming_bytes = sqlite3_column_int64(stm, 3);
+ data.cnt.outgoing_bytes = sqlite3_column_int64(stm, 4);
data.ifname = (char *)sqlite3_column_text(stm, 5);
+ data.imsi = (char *)sqlite3_column_text(stm, 6);
if (rule->granularity) {
- interval.from = sqlite3_column_int64(stm, 6);
+ interval.from = sqlite3_column_int64(stm, 7);
interval.to = interval.from + rule->granularity;
}
- data.app_id = (char *)sqlite3_column_text(stm, 0);
-
if (info_cb(&data, user_data) == RESOURCED_CANCEL)
rc = SQLITE_DONE; /* emulate end of data */
diff --git a/src/network/generic-netlink.c b/src/network/generic-netlink.c
index a7f0e8e7..8a58372e 100644
--- a/src/network/generic-netlink.c
+++ b/src/network/generic-netlink.c
@@ -53,54 +53,11 @@
#define NESTED_MCAST_MAX 256
#define MAX_PAYLOAD 1024 /* maximum payload size */
-/**
- * @desc accepts opaque pointer
- * extracts command id
- */
-inline int netlink_get_command(struct genl *nl_ans)
-{
- return nl_ans->g.cmd;
-}
-
uint32_t netlink_get_family(struct genl *nl_ans)
{
return nl_ans->n.nlmsg_type;
}
-static void fill_traf_stat_list(char *buffer, __u16 count,
- traffic_stat_tree *stats)
-{
- struct traffic_event *cur = (struct traffic_event *)buffer;
-
- while (count) {
- struct traffic_stat *to_insert;
- struct classid_iftype_key *key;
-
- to_insert = g_new(struct traffic_stat, 1);
- if (!to_insert) {
- _D("Can't allocate %d bytes for traffic_stat\n", sizeof(struct traffic_stat));
- return;
- }
-
- key = g_new(struct classid_iftype_key, 1);
-
- if (!key) {
- _D("Can't allocate %d bytes for classid_iftype_key\n", sizeof(struct classid_iftype_key));
- g_free((gpointer)to_insert);
- return;
- }
-
- to_insert->bytes = cur->bytes;
- to_insert->ifindex = cur->ifindex;
- key->classid = cur->sk_classid ?
- cur->sk_classid : RSML_UNKNOWN_CLASSID;
- key->iftype = get_iftype(cur->ifindex);
- g_tree_insert((GTree *) stats, (gpointer)key, to_insert);
- --count;
- ++cur;
- }
-}
-
/*
* Send netlink message to kernel
*/
@@ -473,70 +430,6 @@ int send_restriction(int sock, const pid_t pid, const int family_id,
return r;
}
-static void _process_answer(struct netlink_serialization_params *params)
-{
- struct genl *nl_ans = params->ans;
- traffic_stat_tree *stats = params->stat_tree;
- ssize_t remains;
- char *buffer;
- struct nlattr *first_na, *second_na;
- int first_len;
- int count = 0;
-
- remains = GENLMSG_PAYLOAD(&nl_ans->n);
- if (remains <= 0)
- return;
-
- /* parse reply message */
- first_na = (struct nlattr *)GENLMSG_DATA(nl_ans);
-
- /* inline nla_next() */
- first_len = NLA_ALIGN(first_na->nla_len);
-
- second_na = (struct nlattr *) ((char *) first_na + first_len);
- remains -= first_len;
-
- /* but we need data_attr->nla_len */
- buffer = (char *) malloc((size_t)remains);
- if (buffer == NULL)
- return;
-
- if (first_na->nla_type == TRAF_STAT_COUNT) {
- count = *(__u16 *) NLA_DATA(first_na);
- memcpy(buffer, (char *) NLA_DATA(second_na),
- second_na->nla_len);
- } else {
- _D("Expected attribute %d got %d", TRAF_STAT_COUNT, first_na->nla_type);
- }
-
- if (count > 0)
- fill_traf_stat_list(buffer, count, stats);
- free(buffer);
-
-}
-
-netlink_serialization_command *netlink_create_command(
- struct netlink_serialization_params *params)
-{
- static netlink_serialization_command command = {0,};
- const int netlink_command = netlink_get_command(params->ans);
-
- command.params = *params;
-
- if (netlink_command == TRAF_STAT_C_GET_CONN_IN) {
- command.deserialize_answer = _process_answer;
- command.params.stat_tree = params->carg->in_tree;
- } else if (netlink_command == TRAF_STAT_C_GET_PID_OUT) {
- command.deserialize_answer = _process_answer;
- command.params.stat_tree = params->carg->out_tree;
- } else {
- _E("Unknown command!");
- return NULL;
- }
-
- return &command;
-}
-
resourced_ret_c process_netlink_restriction_msg(const struct genl *ans,
struct traffic_restriction *restriction, uint8_t *command)
{
diff --git a/src/network/iface-cb.c b/src/network/iface-cb.c
index 6f2457fc..b538239b 100644
--- a/src/network/iface-cb.c
+++ b/src/network/iface-cb.c
@@ -227,6 +227,5 @@ void resourced_iface_finalize(void)
ecore_main_fd_handler_del(iface_ecore_fd_handler);
shutdown(iface_fd, 2);
close(iface_fd);
- finalize_iftypes();
g_list_free_full(ifcallbacks, free);
}
diff --git a/src/network/iface.c b/src/network/iface.c
index 5823bfd1..e0631f87 100644
--- a/src/network/iface.c
+++ b/src/network/iface.c
@@ -49,11 +49,10 @@
static int iface_stat[RESOURCED_IFACE_LAST_ELEM - 1];
static GTree *iftypes; /* holds int key and value of type resourced_iface_type */
-static GTree *ifnames; /* for keeping ifype - interface name association */
-static pthread_rwlock_t iftypes_guard = PTHREAD_RWLOCK_INITIALIZER;
-static pthread_rwlock_t ifnames_guard = PTHREAD_RWLOCK_INITIALIZER;
+static GSList *ifnames; /* for keeping ifype - interface name association */
+static pthread_rwlock_t iftypes_guard = PTHREAD_RWLOCK_INITIALIZER;
static const char *UEVENT_FMT = "/sys/class/net/%s/uevent";
static const char *DEVTYPE_KEY = "DEVTYPE";
@@ -71,6 +70,12 @@ struct iface_relation {
char ifname[MAX_NAME_LENGTH];
};
+struct iface_status {
+ bool active;
+ char ifname[MAX_NAME_LENGTH];
+ resourced_iface_type iftype;
+};
+
static gint compare_int(gconstpointer a, gconstpointer b,
gpointer UNUSED userdata)
{
@@ -101,22 +106,42 @@ static void put_iftype_to_tree(GTree *iftypes_tree, int ifindex, int iftype)
g_tree_replace(iftypes_tree, (gpointer)ifindex, new_value);
}
-static void put_ifname_to_tree(GTree *ifnames_tree, char *ifname, int iftype)
+static void keep_ifname(GSList **ifnames_list, char *ifname, int iftype)
{
- int name_len = strlen(ifname) + 1;
- gpointer new_value = (gpointer)malloc(name_len);
- if (!new_value) {
- _E("Malloc of put_ifname_to_tree failed\n");
- return;
+ GSList *iter;
+ bool found = false;
+ struct iface_status *value;
+ ret_msg_if (!ifnames_list || !ifname, "Please provide valid argument!");
+
+ gslist_for_each_item(iter, *ifnames_list) {
+ struct iface_status *cur = (struct iface_status *)iter->data;
+ if (cur->iftype == iftype && !strcmp(cur->ifname, ifname)) {
+ cur->active = true;
+ found = true;
+ }
}
- strncpy(new_value, ifname, name_len);
- if (!ifnames_tree) {
- free(new_value);
- _E("Please provide valid argument!");
+ if (found)
return;
+
+ _D("Add new entry into ifnames");
+ value = (struct iface_status *)malloc(
+ sizeof(struct iface_status));
+
+ ret_msg_if (!value, "Can't allocate memory for iface_status\n");
+ value->active = true; /* we're putting it => it's active now */
+ value->iftype = iftype;
+ STRING_SAVE_COPY(value->ifname, ifname);
+ *ifnames_list = g_slist_prepend(*ifnames_list, value);
+}
+
+static void reset_active_ifnames(GSList *ifnames_list)
+{
+ GSList *iter;
+ gslist_for_each_item(iter, ifnames_list) {
+ struct iface_status *value = (struct iface_status *)iter->data;
+ value->active = false;
}
- g_tree_replace(ifnames_tree, (gpointer)iftype, new_value);
}
static resourced_iface_type get_iftype_from_tree(GTree *iftypes_tree, int ifindex)
@@ -247,7 +272,6 @@ int init_iftype(void)
resourced_iface_type iftype;
struct if_nameindex *ids = if_nameindex();
GTree *iftypes_next = create_iface_tree();
- GTree *ifnames_next = create_iface_tree();
if (ids == NULL) {
_E("Failed to initialize iftype table! errno: %d, %s",
@@ -263,16 +287,22 @@ int init_iftype(void)
NET_INTERFACE_NAMES_FILE);
}
+ reset_active_ifnames(ifnames);
iface_stat_allowance();
for (i = 0; ids[i].if_index != 0; ++i) {
if (!is_address_exists(ids[i].if_name))
continue;
iftype = read_iftype(ids[i].if_name);
+ /* don't put unknown network interface into list */
+ if (iftype == RESOURCED_IFACE_UNKNOWN) {
+ _D("unknown ifname %s, ifype %d", ids[i].if_name, iftype);
+ continue;
+ }
put_iftype_to_tree(iftypes_next, ids[i].if_index, iftype);
/* we know here iftype/ids[i].if_name, lets populate
* ifnames_tree */
- put_ifname_to_tree(ifnames_next, ids[i].if_name, iftype);
+ keep_ifname(&ifnames, ids[i].if_name, iftype);
_D("ifname %s, ifype %d", ids[i].if_name, iftype);
}
@@ -280,14 +310,13 @@ int init_iftype(void)
if_freenameindex(ids);
reset_tree(iftypes_next, &iftypes, &iftypes_guard);
- reset_tree(ifnames_next, &ifnames, &ifnames_guard);
return RESOURCED_ERROR_NONE;
}
void finalize_iftypes(void)
{
reset_tree(NULL, &iftypes, &iftypes_guard);
- reset_tree(NULL, &ifnames, &ifnames_guard);
+ g_slist_free_full(ifnames, free);
g_slist_free_full(ifnames_relations, free);
}
@@ -314,77 +343,83 @@ resourced_iface_type convert_iftype(const char *buffer)
return RESOURCED_IFACE_UNKNOWN;
}
-int is_allowed_ifindex(int ifindex)
+int is_counting_allowed(resourced_iface_type iftype)
{
- return iface_stat[get_iftype(ifindex)];
+ return iface_stat[iftype];
}
-resourced_iface_type get_iftype(int ifindex)
+API resourced_iface_type get_iftype(int ifindex)
{
return get_iftype_from_tree(iftypes, ifindex);
}
-static gboolean print_ifname(gpointer key, gpointer value, gpointer data)
+static char *lookup_ifname(GSList *ifnames_list, int iftype)
{
- _D("ifname %s", (char *)value);
- return FALSE;
-}
-
-static char *get_ifname_from_tree(GTree *ifnames_tree, int iftype)
-{
- char *ret = NULL;
+ GSList *iter;
- ret_value_msg_if(!ifnames_tree, NULL, "Please provide valid argument!");
+ ret_value_msg_if(!ifnames_list, NULL, "Please provide valid argument!");
- pthread_rwlock_rdlock(&ifnames_guard);
- ret = (char *)g_tree_lookup(ifnames_tree, (gpointer)iftype);
- pthread_rwlock_unlock(&ifnames_guard);
- if (ret == NULL)
- g_tree_foreach(ifnames_tree, print_ifname, NULL);
+ gslist_for_each_item(iter, ifnames_list) {
+ struct iface_status *value = (struct iface_status *)iter->data;
+ if (value->iftype == iftype)
+ return value->ifname;
+ }
- return ret;
+ return NULL;
}
char *get_iftype_name(resourced_iface_type iftype)
{
- return get_ifname_from_tree(ifnames, iftype);
-}
-
-static gboolean search_loopback(gpointer key,
- gpointer value,
- gpointer data)
-{
- int *res = (int *)data;
- if (!value)
- return FALSE;
- *res = *(int *)value == RESOURCED_IFACE_UNKNOWN ? TRUE : FALSE;
- return *res;
+ return lookup_ifname(ifnames, iftype);
}
-static bool is_only_loopback(GTree *iftypes_tree)
+resourced_iface_type get_iftype_by_name(char *name)
{
- int nodes = g_tree_nnodes(iftypes_tree);
- int res = 0;
+ GSList *iter;
+ ret_value_msg_if(name == NULL, RESOURCED_IFACE_UNKNOWN,
+ "Invalid argument");
- if (nodes > 1)
- return false;
+ gslist_for_each_item(iter, ifnames) {
+ struct iface_status *value = (struct iface_status *)iter->data;
+ if (!strcmp(value->ifname, name))
+ return value->iftype;
+ }
- g_tree_foreach(iftypes_tree, search_loopback, &res);
- return res;
+ return RESOURCED_IFACE_UNKNOWN;
}
+/* now used only in ./src/network/ktgrabber-restriction.c:285 */
void for_each_ifindex(ifindex_iterator iter, void(*empty_func)(void *),
void *data)
{
pthread_rwlock_rdlock(&iftypes_guard);
- if (!is_only_loopback(iftypes))
- g_tree_foreach(iftypes, (GTraverseFunc)iter, data);
- else if (empty_func)
+ g_tree_foreach(iftypes, (GTraverseFunc)iter, data);
+
+ if (empty_func)
empty_func(data);
pthread_rwlock_unlock(&iftypes_guard);
}
+void for_each_ifnames(ifnames_iterator iter_cb, void(*empty_func)(void *),
+ void *data)
+{
+ GSList *iter;
+ gslist_for_each_item(iter, ifnames) {
+ struct iface_status *value = (struct iface_status *)iter->data;
+ /* as before invoke cb only for active interfaces */
+ if (!value->active)
+ continue;
+
+ if (iter_cb(value->iftype, value->ifname, data) == TRUE)
+ break;
+ }
+
+ if (empty_func)
+ empty_func(data);
+
+}
+
void set_wifi_allowance(const resourced_option_state wifi_option)
{
iface_stat[RESOURCED_IFACE_WIFI] = wifi_option == RESOURCED_OPTION_ENABLE ? 1 : 0;
@@ -394,3 +429,4 @@ void set_datacall_allowance(const resourced_option_state datacall_option)
{
iface_stat[RESOURCED_IFACE_DATACALL] = datacall_option == RESOURCED_OPTION_ENABLE ? 1 : 0;
}
+
diff --git a/src/common/app-stat.h b/src/network/include/app-stat.h
index 6818fadd..090e77e9 100644
--- a/src/common/app-stat.h
+++ b/src/network/include/app-stat.h
@@ -33,6 +33,7 @@
#include <sys/types.h>
#include "const.h"
+#include "config.h"
#include "data_usage.h"
#include "daemon-options.h"
#include "transmission.h"
@@ -55,28 +56,31 @@ struct application_stat {
uint32_t delta_snd;
uint32_t delta_rcv;
+#ifndef CONFIG_DATAUSAGE_NFACCT
pid_t pid;
int ifindex;
+#endif
resourced_roaming_type is_roaming;
-};
-/*
-* Structure for holding serialized data from kernel @see traffic_event
-*/
-struct traffic_stat {
- unsigned long bytes;
- int ifindex;
+ /* foreground/background state is here,
+ * not in classid_iftype_key, it means
+ * we'll not able to handle simultaneously
+ * counter per one application for background and
+ * foreground withing one counting cycle,
+ * so every time application goes to background/foreground
+ * we'll request its counter update */
+ resourced_state_t ground;
};
struct classid_iftype_key
{
u_int32_t classid;
int iftype;
- char ifname[MAX_NAME_LENGTH];
+ /* pointer to telephony's imsi */
+ char *imsi;
+ char ifname[MAX_IFACE_LENGTH];
};
-typedef GTree traffic_stat_tree;
-
struct application_stat_tree {
GTree *tree;
time_t last_touch_time;
@@ -87,13 +91,16 @@ struct application_stat_tree *create_app_stat_tree(void);
void free_app_stat_tree(struct application_stat_tree *tree);
void nulify_app_stat_tree(struct application_stat_tree **tree);
-traffic_stat_tree *create_traffic_stat_tree(void);
-void free_traffic_stat_tree(traffic_stat_tree *list);
+struct counter_arg;
+#ifdef CONFIG_DATAUSAGE_NFACCT
+void fill_nfacct_result(char *cnt_name, uint64_t bytes,
+ struct counter_arg *carg);
+#else
+/* It's not same function used at netacct and it's only used at ktgrabber. */
+void fill_app_stat_result(int ifindex, int classid, uint64_t bytes, int iotype,
+ struct counter_arg *carg);
+#endif
-resourced_ret_c prepare_application_stat(traffic_stat_tree *tree_in,
- traffic_stat_tree *tree_out,
- struct application_stat_tree *result,
- volatile struct daemon_opts *opts);
#endif /* _RESOURCED_APPLICATION_STAT_H_ */
diff --git a/src/network/include/counter.h b/src/network/include/counter.h
index 3e89fdce..b05bb5d8 100644
--- a/src/network/include/counter.h
+++ b/src/network/include/counter.h
@@ -33,6 +33,8 @@
#include <Ecore.h>
+#define RESOURCED_BACKGROUND_APP_NAME "BACKGROUND"
+
struct counter_arg {
int sock;
int ans_len;
@@ -46,13 +48,19 @@ struct counter_arg {
int noti_fd;
Ecore_Fd_Handler *noti_fd_handler;
#endif
+ int serialized_counters; /* number of counters which was serialized in
+ current request */
struct daemon_opts *opts;
struct application_stat_tree *result;
- traffic_stat_tree *in_tree;
- traffic_stat_tree *out_tree;
+ time_t last_run_time;
+ /* main timer for getting kernel counters */
Ecore_Timer *ecore_timer;
+ /* handler for kernel's fd for getting counters from ktgrabber/nfacct */
Ecore_Fd_Handler *ecore_fd_handler;
+ /* timer for separate obtaining values from kernel and store result into db */
Ecore_Timer *store_result_timer;
+ /* timer for reset old statistics */
+ Ecore_Timer *erase_timer;
};
/**
diff --git a/src/network/include/datausage-common.h b/src/network/include/datausage-common.h
index 49b8cf9a..b626d025 100644
--- a/src/network/include/datausage-common.h
+++ b/src/network/include/datausage-common.h
@@ -32,6 +32,8 @@
#include <resourced.h>
+#include "counter.h"
+#include "nfacct-rule.h"
#include "iface.h"
enum netstat_control_type {
@@ -61,5 +63,28 @@ iface_callback *create_counter_callback(void);
struct nfacct_rule;
void keep_counter(struct nfacct_rule *counter);
+/* remove counter from tree and execute its rule */
+void finalize_counter(struct nfacct_rule *counter);
+
+void set_finalize_flag(struct nfacct_rule *counter);
+void update_counter_quota_value(struct nfacct_rule *counter, uint64_t bytes);
+void extract_restriction_list(struct counter_arg *arg, GSList **rst_list);
+resourced_state_t get_app_ground(struct nfacct_rule *counter);
+
+/**
+ * @desc mark appropriate nfacct by app_id as background
+ */
+void mark_background(const char *app_id);
+
+/**
+ * @desc move all pids of existing nfacct from background cgroup,
+ * to appropriate apps cgroups
+ */
+void foreground_apps(struct counter_arg *carg);
+
+/**
+ * @desc move all pids of existing nfacct to background cgroup
+ */
+void background_apps(struct counter_arg *carg);
#endif /* __RESOURCED_NETSTAT_COMMON_H__ */
diff --git a/src/network/include/datausage-quota-processing.h b/src/network/include/datausage-quota-processing.h
index 016520ab..c4d867fe 100644
--- a/src/network/include/datausage-quota-processing.h
+++ b/src/network/include/datausage-quota-processing.h
@@ -30,21 +30,34 @@
#define _TRESOURCED_DATAUSAGE_QUOTA_PROCESSING_H_
#include <sqlite3.h>
+#include <stdbool.h>
-#include "app-stat.h"
-#include "resourced.h"
+#include "data_usage.h"
+
+struct serialization_quota {
+ int time_period;
+ int64_t snd_quota;
+ int64_t rcv_quota;
+ int snd_warning_threshold;
+ int rcv_warning_threshold;
+ resourced_state_t quota_type;
+ resourced_iface_type iftype;
+ time_t start_time;
+ resourced_roaming_type roaming_type;
+ char *imsi_hash;
+};
/*
* Store data in effective quota
*/
void flush_quota_table(void);
+struct counter_arg;
/*
* Quota processing. It's apply quota if needed.
* And actualize current quotas state.
*/
-resourced_ret_c process_quota(struct application_stat_tree *apps,
- volatile struct daemon_opts *opts);
+resourced_ret_c process_quota(struct counter_arg *carg);
/*
* Finish working with quotas
@@ -54,8 +67,30 @@ void finalize_quotas(void);
/*
* Delete quota and drop remove restriction
*/
-void update_quota_state(const char *app_id, const resourced_iface_type iftype,
- const time_t start_time, const int time_period,
- const resourced_roaming_type roaming);
+void update_quota_state(const char *app_id, const int quota_id,
+ struct serialization_quota *ser_quota);
+
+void remove_quota_from_counting(const char *app_id, const resourced_iface_type iftype,
+ const resourced_roaming_type roaming,
+ const char *imsi);
+
+void clear_effective_quota(const char *app_id,
+ const resourced_iface_type iftype,
+ const resourced_roaming_type roaming,
+ const char *imsi_hash);
+
+resourced_ret_c get_quota_by_id(const int quota_id, data_usage_quota *du_quota);
+resourced_ret_c get_quota_by_appid(const char* app_id, const char *imsi_hash,
+ const resourced_iface_type iftype, resourced_roaming_type roaming_type,
+ data_usage_quota *du_quota, int *quota_id, resourced_state_t ground);
+/**
+ * @desc return true if we have applied background quota
+ */
+bool get_background_quota(void);
+
+
+bool check_quota_applied(const char *app_id, const resourced_iface_type iftype,
+ const resourced_roaming_type roaming, const char *imsi,
+ const resourced_state_t ground, int *quota_id);
#endif /* _TRESOURCED_DATAUSAGE_QUOTA_PROCESSING_H_ */
diff --git a/src/network/include/datausage-restriction.h b/src/network/include/datausage-restriction.h
index e1ee46a0..21d5d12c 100644
--- a/src/network/include/datausage-restriction.h
+++ b/src/network/include/datausage-restriction.h
@@ -28,6 +28,8 @@
#define _RESOURCED_RESTRICTION_H_
#include <sqlite3.h>
+#include <stdbool.h>
+
#include "resourced.h"
#include "data_usage.h"
#include "transmission.h"
@@ -42,7 +44,8 @@ resourced_ret_c update_restriction_db(
const int rcv_limit, const int snd_limit,
const resourced_restriction_state rst_state,
const int quota_id,
- const resourced_roaming_type roaming);
+ const resourced_roaming_type roaming,
+ const char *ifname);
/**
* @desc Get restriction info from database
@@ -59,17 +62,23 @@ resourced_ret_c get_restriction_info(const char *app_id,
resourced_ret_c process_kernel_restriction(
const u_int32_t classid,
const resourced_net_restrictions *rst,
- const enum traffic_restriction_type rst_type);
+ const enum traffic_restriction_type rst_type,
+ const int quota_id);
resourced_ret_c proc_keep_restriction(
const char *app_id, int quota_id, const resourced_net_restrictions *rst,
- const enum traffic_restriction_type rst_type);
+ const enum traffic_restriction_type rst_type,
+ bool skip_kernel_op);
resourced_ret_c remove_restriction_local(const char *app_id,
- const resourced_iface_type iftype);
+ const resourced_iface_type iftype,
+ const int quota_id,
+ const char *imsi,
+ const resourced_state_t ground);
resourced_ret_c exclude_restriction_local(const char *app_id,
const int quota_id,
- const resourced_iface_type iftype);
+ const resourced_iface_type iftype,
+ const char *imsi);
#endif /* _RESOURCED_RESTRICTION_H_ */
diff --git a/src/network/include/datausage-vconf-common.h b/src/network/include/datausage-vconf-common.h
index 5d23d769..3e1a870a 100644
--- a/src/network/include/datausage-vconf-common.h
+++ b/src/network/include/datausage-vconf-common.h
@@ -25,5 +25,4 @@ enum restriction_state {
};
resourced_ret_c restriction_check_limit_status(int *retval);
-resourced_ret_c restriction_read_quota(int *quota);
void restriction_set_status(int value);
diff --git a/src/network/include/roaming.h b/src/network/include/db-guard.h
index d527fd92..4c52f4e4 100644
--- a/src/network/include/roaming.h
+++ b/src/network/include/db-guard.h
@@ -1,7 +1,7 @@
/*
* resourced
*
- * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2000 - 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.
@@ -18,25 +18,21 @@
*/
/*
+ * @file db-guard.h
*
- * @file roaming.h
+ * @desc This guard procedures are responsible for period db erasing
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
*
- * @desc Roaming persistent object. Due roaming changes not so often we can keep it in
- * our memory and handle roaming changes.
*/
-#ifndef _RSML_LIBS_ROAMING_H
-#define _RSML_LIBS_ROAMING_H
-
-#include "data_usage.h"
+#ifndef _RESOURCED_DB_GUARD_H_
+#define _RESOURCED_DB_GUARD_H_
-/**
- * @brief Just get roaming state.
- */
-resourced_roaming_type get_roaming(void);
+void change_db_entries_num_num(int num);
-typedef void(*roaming_cb)(void);
+struct counter_arg;
+resourced_ret_c resourced_init_db_guard(struct counter_arg *carg);
-void regist_roaming_cb(roaming_cb cb);
+#endif /* _RESOURCED_DB_GUARD_H_ */
-#endif /* _RSML_LIBS_ROAMING_H*/
diff --git a/src/network/include/iface.h b/src/network/include/iface.h
index 3e70d0ef..05737d0f 100644
--- a/src/network/include/iface.h
+++ b/src/network/include/iface.h
@@ -43,10 +43,13 @@ typedef struct {
int init_iftype(void);
void finalize_iftypes(void);
-int is_allowed_ifindex(int ifindex);
-
+/* TODO remove ktgrabber */
resourced_iface_type get_iftype(int ifindex);
+
+int is_counting_allowed(resourced_iface_type iftype);
+
char *get_iftype_name(resourced_iface_type iftype);
+resourced_iface_type get_iftype_by_name(char *name);
bool is_address_exists(const char *name);
resourced_iface_type convert_iftype(const char *buffer);
@@ -54,12 +57,19 @@ resourced_iface_type convert_iftype(const char *buffer);
void set_wifi_allowance(const resourced_option_state wifi_option);
void set_datacall_allowance(const resourced_option_state datacall_option);
+/* TODO remove it when ktgrabber solution will be removed */
typedef int(*ifindex_iterator)(int ifindex,
resourced_iface_type iftype, void *data);
void for_each_ifindex(ifindex_iterator iter, void(*empty_func)(void *),
void *data);
+typedef int(*ifnames_iterator)(resourced_iface_type iftype, char *ifname,
+ void *data);
+
+void for_each_ifnames(ifnames_iterator iter, void(*empty_func)(void *),
+ void *data);
+
typedef GList iface_callbacks;
#endif /*TRESOURCED_LIBS_NET_IFACE_H_*/
diff --git a/src/network/include/net-cls-cgroup.h b/src/network/include/net-cls-cgroup.h
index 70eec153..1ec70506 100644
--- a/src/network/include/net-cls-cgroup.h
+++ b/src/network/include/net-cls-cgroup.h
@@ -66,12 +66,11 @@ char *get_app_id_by_classid(const u_int32_t classid, const bool update_state);
u_int32_t get_classid_by_app_id(const char *app_id, int create);
/**
- * @desc take classid from net_cls cgroup with name pkg_name
- * @param pkg_name - name of the cgroup
- * @param create - in case of true - create cgroup if it's not exists
- * @return classid
+ * @desc create cgroup, generate classid and put classid into cgroup
*/
-u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create);
+resourced_ret_c make_net_cls_cgroup(const char *pkg_name, u_int32_t classid);
+
+resourced_ret_c place_pids_to_net_cgroup(const int pid, const char *pkg_name);
/**
* @desc Make net_cls cgroup and put in it the given pid and
@@ -83,4 +82,11 @@ u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create);
resourced_ret_c make_net_cls_cgroup_with_pid(const int pid,
const char *pkg_name);
+struct counter_arg;
+/**
+ * @desc this function makes net_cls cgroup and put pids into it
+ * */
+void create_net_background_cgroup(struct counter_arg *carg);
+
+
#endif /*_RESOURCED_NET_CLS_CGROUP_H_*/
diff --git a/src/network/include/netlink-restriction.h b/src/network/include/netlink-restriction.h
index 1df4f035..53175314 100644
--- a/src/network/include/netlink-restriction.h
+++ b/src/network/include/netlink-restriction.h
@@ -39,6 +39,7 @@
* rst_type - type of restriction on the basis of which the restriction
* can be applied, removed or excluded.
* classid - id, that generated for each application in the cgroup
+ * quota_id - quota_id to store in nf_cntr tree
* iftype - network interface type to proccess restriction
* send_limit - amount number of engress bytes allowed for restriction
* rcv_limit - amount number of ingress bytes allowed for restriction
@@ -46,10 +47,11 @@
* rcv_warning_limit - threshold for warning notification on ingress bytes
*/
int send_net_restriction(const enum traffic_restriction_type rst_type,
- const u_int32_t classid,
+ const u_int32_t classid, const int quota_id,
const resourced_iface_type iftype,
const int send_limit, const int rcv_limit,
const int snd_warning_threshold,
- const int rcv_warning_threshold);
+ const int rcv_warning_threshold,
+ const char *ifname);
#endif /* RESOURCED_NET_RESTRICTION_H_ */
diff --git a/src/network/include/nfacct-rule.h b/src/network/include/nfacct-rule.h
index 16b00e1d..1886bdc8 100644
--- a/src/network/include/nfacct-rule.h
+++ b/src/network/include/nfacct-rule.h
@@ -61,12 +61,29 @@ typedef enum {
NFACCT_COUNTER,
NFACCT_WARN,
NFACCT_BLOCK,
+ NFACCT_TETH_COUNTER,
NFACCT_RULE_LAST_ELEM,
} nfacct_rule_intend;
+enum nfnl_acct_flags {
+ NFACCT_F_QUOTA_PKTS = (1 << 0),
+ NFACCT_F_QUOTA_BYTES = (1 << 1),
+ NFACCT_F_OVERQUOTA = (1 << 2), /* can't be set from userspace */
+};
+
+/* it's better to have
+ * base nfacct_rule with following fields:
+ * name, ifname, pid, classid, iftype, intend, carg, iptables_rule
+ *
+ * and inherited nfacct_rule_counter and nfacct_rule_restriction
+ * with additional field:
+ * quota, quota_id, roaming, rst_state
+ *
+ * But ANSI C doesn't support inheritance.
+ */
struct nfacct_rule {
char name[MAX_NAME_LENGTH];
- char ifname[MAX_NAME_LENGTH];
+ char ifname[MAX_IFACE_LENGTH];
pid_t pid;
u_int32_t classid;
@@ -76,6 +93,9 @@ struct nfacct_rule {
struct counter_arg *carg;
resourced_ret_c(*iptables_rule)(struct nfacct_rule *counter);
u_int64_t quota;
+ int quota_id;
+ resourced_roaming_type roaming;
+ resourced_restriction_state rst_state;
};
struct counter_arg;
@@ -83,7 +103,11 @@ struct counter_arg;
void generate_counter_name(struct nfacct_rule *counter);
bool recreate_counter_by_name(char *cnt_name, struct nfacct_rule *counter);
-resourced_ret_c nfacct_send_get(struct counter_arg *carg);
+resourced_ret_c nfacct_send_get_all(struct counter_arg *carg);
+resourced_ret_c nfacct_send_get_counters(struct counter_arg *carg,
+ const char *name);
+resourced_ret_c nfacct_send_get(struct nfacct_rule *rule);
+resourced_ret_c nfacct_send_del(struct nfacct_rule *counter);
resourced_ret_c nfacct_send_initiate(struct counter_arg *carg);
resourced_ret_c exec_iptables_cmd(const char *cmd_buf, pid_t *pid);
diff --git a/src/network/include/nl-helper.h b/src/network/include/nl-helper.h
index 0ef417b8..709b512f 100644
--- a/src/network/include/nl-helper.h
+++ b/src/network/include/nl-helper.h
@@ -98,7 +98,7 @@ struct genl {
};
struct netlink_serialization_params {
- traffic_stat_tree *stat_tree;
+ int direction;
struct genl *ans;
struct counter_arg *carg;
int (*eval_attr)(struct rtattr *attr_list[__NFACCT_MAX],
diff --git a/src/network/include/notification.h b/src/network/include/notification.h
index fb28122f..688b9242 100644
--- a/src/network/include/notification.h
+++ b/src/network/include/notification.h
@@ -1,7 +1,7 @@
/*
* resourced
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * 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.
@@ -29,8 +29,29 @@
#ifndef _RESOURCED_DATAUSAGE_NOTIFICATION_H
#define _RESOURCED_DATAUSAGE_NOTIFICATION_H
-void send_restriction_notification(const char *appid);
-void send_restriction_warn_notification(const char *appid);
+#include "data_usage.h"
-#endif /* _RESOURCED_DATAUSAGE_NOTIFICATION_H */
+/* NOTI. */
+#define WARNING_NOTI_ON "WarningNotiOn"
+#define WARNING_NOTI_OFF "WarningNotiOff"
+#define DISABLE_NOTI_ON "DisabledNotiOn"
+#define DISABLE_NOTI_OFF "DisabledNotiOff"
+
+
+/* POPUP */
+#define POPUP_KEY "_SYSPOPUP_CONTENT_"
+#define POPUP_KEY_LIMIT "_DATAUSAGE_LIMIT_"
+#define POPUP_VALUE_DISABLED "datausage_disabled"
+#define POPUP_VALUE_WARNING "datausage_warning"
+#define METHOD_CALL_POPUP "DatausagePopupLaunch"
+enum noti_type {
+ WARNING_NOTI,
+ DISABLE_NOTI,
+};
+
+void check_and_clear_all_noti(void);
+void send_restriction_notification(const char *appid, data_usage_quota *du_quota);
+void send_restriction_warn_notification(const char *appid, data_usage_quota *du_quota);
+
+#endif /* _RESOURCED_DATAUSAGE_NOTIFICATION_H */
diff --git a/src/network/include/protocol-info.h b/src/network/include/protocol-info.h
deleted file mode 100644
index 3a8d4acd..00000000
--- a/src/network/include/protocol-info.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- *
- */
-
-/*
- * @file protocol-info.h
- *
- * @desc Network protocol entity: now it's only for
- * datacall network interface type
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#ifndef RESOURCED_PROTOCOL_INFO_NET_IFACE_H_
-#define RESOURCED_PROTOCOL_INFO_NET_IFACE_H_
-
-#include "data_usage.h"
-
-void init_hw_net_protocol_type(void);
-
-void finalize_hw_net_protocol_type(void);
-
-resourced_hw_net_protocol_type get_hw_net_protocol_type(
- const resourced_iface_type iftype);
-
-#endif /* RESOURCED_PROTOCOL_INFO_NET_IFACE_H_ */
diff --git a/src/network/include/restriction-handler.h b/src/network/include/restriction-handler.h
index 28a72975..2fcd4cc9 100644
--- a/src/network/include/restriction-handler.h
+++ b/src/network/include/restriction-handler.h
@@ -28,7 +28,7 @@
#define _RESOURCED_RESTRICTION_HANDLER_H_
#include "iface.h"
-#include "roaming.h"
+#include "telephony.h"
/**
* @brief This function allocates structure
@@ -37,12 +37,6 @@
*/
iface_callback *create_restriction_callback(void);
-/**
- * @brief This function returns pointer to roaming
- * callback. No need to free memory.
- */
-roaming_cb get_roaming_restriction_cb(void);
-
void reactivate_restrictions(void);
typedef GList list_restrictions_info;
diff --git a/src/network/include/storage.h b/src/network/include/storage.h
index 97fc9b31..9f0b6f36 100644
--- a/src/network/include/storage.h
+++ b/src/network/include/storage.h
@@ -47,10 +47,9 @@ resourced_ret_c init_database(const char *filename);
/**
* @desc Store result list to database.
* @param stats - List of resolved application information
- * @param flush_period - Time interval for storing data
* @return 1 if flushed, 0 if not
*/
-int store_result(struct application_stat_tree *stats, int flush_period);
+int store_result(struct application_stat_tree *stats);
/**
* @desc Just close sqlite statements.
diff --git a/src/network/include/telephony.h b/src/network/include/telephony.h
new file mode 100644
index 00000000..7d6ee922
--- /dev/null
+++ b/src/network/include/telephony.h
@@ -0,0 +1,49 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 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 telephony.h
+ *
+ * @desc Roaming persistent object. Due roaming changes not so often we can keep it in
+ * our memory and handle roaming changes.
+ */
+
+#ifndef __RESOURCED_TELEPHONY_H
+#define __RESOURCED_TELEPHONY_H
+
+#include <stdbool.h>
+#include "data_usage.h"
+
+#define VCONF_TELEPHONY_DEFAULT_DATA_SERVICE "db/telephony/dualsim/default_data_service"
+
+resourced_roaming_type get_current_roaming(void);
+resourced_hw_net_protocol_type get_current_protocol(resourced_iface_type iftype);
+
+/**
+ * @brief Get international mobile subscriber identity from saved list for current modem
+ */
+char *get_current_modem_imsi(void);
+char *get_imsi_hash(char *imsi);
+bool check_event_in_current_modem(const char *imsi_hash,
+ const resourced_iface_type iftype);
+
+void finilize_telephony(void);
+
+#endif /* __RESOURCED_TELEPHONY_H */
diff --git a/src/network/include/tethering-restriction.h b/src/network/include/tethering-restriction.h
index 047cc058..1b962401 100644
--- a/src/network/include/tethering-restriction.h
+++ b/src/network/include/tethering-restriction.h
@@ -29,6 +29,7 @@
#ifndef RESOURCED_TETHERING_RESTRICTION_H_
#define RESOURCED_TETHERING_RESTRICTION_H_
+#include "trace.h"
#include "transmission.h"
#define PATH_TO_PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
diff --git a/src/network/dummy_roaming.c b/src/network/join-dummy.c
index c67fee65..cc816c7b 100644
--- a/src/network/dummy_roaming.c
+++ b/src/network/join-dummy.c
@@ -1,7 +1,7 @@
/*
- * resourced
+ * resourced
*
- * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ * 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.
@@ -17,27 +17,10 @@
*
*/
-/*
- *
- * @file roaming.c
- *
- * @desc It's dummy implementation for none telephony case.
- */
-
+#include "resourced.h"
#include "macro.h"
-#include "roaming.h"
-#include "trace.h"
-/* for avoiding dependency in this file */
-
-void regist_roaming_cb(roaming_cb UNUSED cb)
+API resourced_ret_c join_app_performance(const char *app_id, const pid_t pid)
{
- _D("ROAMING ISN'T SUPPORTED, CHECK TELEPHONY MODULE");
+ return RESOURCED_ERROR_NONE;
}
-
-resourced_roaming_type get_roaming(void)
-{
- _D("ROAMING ISN'T SUPPORTED, CHECK TELEPHONY MODULE");
- return RESOURCED_ROAMING_UNKNOWN;
-}
-
diff --git a/src/network/ktgrabber-parser.c b/src/network/ktgrabber-parser.c
new file mode 100644
index 00000000..791da0bf
--- /dev/null
+++ b/src/network/ktgrabber-parser.c
@@ -0,0 +1,110 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 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 ktgrabber-parse.c
+ *
+ * @desc User space code for ktgrabber logic
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "generic-netlink.h"
+#include "genl.h"
+#include "trace.h"
+
+
+/**
+ * @desc accepts opaque pointer
+ * extracts command id
+ */
+static inline int netlink_get_command(struct genl *nl_ans)
+{
+ return nl_ans->g.cmd;
+}
+
+static void fill_traf_stat_list(char *buffer, __u16 count,
+ struct netlink_serialization_params *params)
+{
+ struct traffic_event *cur = (struct traffic_event *)buffer;
+
+ while (count) {
+ fill_app_stat_result(cur->ifindex, cur->sk_classid,
+ cur->bytes, params->direction, params->carg);
+ --count;
+ ++cur;
+ }
+}
+
+static void _process_answer(struct netlink_serialization_params *params)
+{
+ struct genl *nl_ans = params->ans;
+ ssize_t remains;
+ char *buffer;
+ struct nlattr *first_na, *second_na;
+ int first_len;
+ int count = 0;
+
+ remains = GENLMSG_PAYLOAD(&nl_ans->n);
+ if (remains <= 0)
+ return;
+
+ /* parse reply message */
+ first_na = (struct nlattr *)GENLMSG_DATA(nl_ans);
+
+ /* inline nla_next() */
+ first_len = NLA_ALIGN(first_na->nla_len);
+
+ second_na = (struct nlattr *) ((char *) first_na + first_len);
+ remains -= first_len;
+
+ /* but we need data_attr->nla_len */
+ buffer = (char *) malloc((size_t)remains);
+ if (buffer == NULL)
+ return;
+
+ if (first_na->nla_type == TRAF_STAT_COUNT) {
+ count = *(__u16 *) NLA_DATA(first_na);
+ memcpy(buffer, (char *) NLA_DATA(second_na),
+ second_na->nla_len);
+ } else {
+ _D("Expected attribute %d got %d", TRAF_STAT_COUNT, first_na->nla_type);
+ }
+
+ if (count > 0)
+ fill_traf_stat_list(buffer, count, params);
+ free(buffer);
+
+}
+
+netlink_serialization_command *netlink_create_command(
+ struct netlink_serialization_params *params)
+{
+ static netlink_serialization_command command = {
+ .deserialize_answer = _process_answer,
+ 0,};
+
+ command.params = *params;
+ command.params.direction = netlink_get_command(params->ans);
+
+ return &command;
+}
+
+
diff --git a/src/network/ktgrabber-restriction.c b/src/network/ktgrabber-restriction.c
index aad8618d..94de128d 100644
--- a/src/network/ktgrabber-restriction.c
+++ b/src/network/ktgrabber-restriction.c
@@ -242,11 +242,12 @@ static resourced_ret_c init_restriction_context(void)
}
int send_net_restriction(const enum traffic_restriction_type rst_type,
- const u_int32_t classid,
+ const u_int32_t classid, const int UNUSED quota_id,
const resourced_iface_type iftype,
const int send_limit, const int rcv_limit,
const int snd_warning_threshold,
- const int rcv_warning_threshold)
+ const int rcv_warning_threshold,
+ const char UNUSED *ifname)
{
struct nf_arg nfarg;
diff --git a/src/network/main.c b/src/network/main.c
index 9b056e4b..8c70e03a 100644
--- a/src/network/main.c
+++ b/src/network/main.c
@@ -76,6 +76,13 @@ API void libresourced_db_initialize_once(void)
return;
}
+ res = sqlite3_exec(database, "PRAGMA locking_mode = NORMAL", 0, 0, 0);
+ if (res != SQLITE_OK) {
+ _E("Can't set locking mode %s", sqlite3_errmsg(database));
+ _E("Skip set busy handler.");
+ return;
+ }
+
/* Set how many times we'll repeat our attempts for sqlite_step */
if (sqlite3_busy_handler(database, resourced_db_busy, NULL) != SQLITE_OK) {
_E("Couldn't set busy handler!");
diff --git a/src/network/net-cls-cgroup.c b/src/network/net-cls-cgroup.c
index 15cde236..f3729c39 100644
--- a/src/network/net-cls-cgroup.c
+++ b/src/network/net-cls-cgroup.c
@@ -24,21 +24,24 @@
*
*/
+#include <dirent.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
#include "appid-helper.h"
-#include "net-cls-cgroup.h"
#include "cgroup.h"
#include "const.h"
+#include "counter.h"
#include "data_usage.h"
+#include "datausage-common.h"
#include "errors.h"
#include "file-helper.h"
#include "macro.h"
+#include "net-cls-cgroup.h"
#include "trace.h"
-#include <dirent.h>
-#include <glib.h>
-#include <stdio.h>
-#include <string.h>
-
#define CUR_CLASSID_PATH "/tmp/cur_classid"
#define CLASSID_FILE_NAME "/net_cls.classid"
#define PATH_TO_NET_CGROUP_DIR "/sys/fs/cgroup/net_cls"
@@ -80,12 +83,15 @@ static int place_classid_to_cgroup(const char *cgroup, const char *subdir,
u_int32_t *classid)
{
char buf[MAX_PATH_LENGTH];
- u_int32_t generated_classid = produce_classid();
- if (classid)
- *classid = generated_classid;
+ u_int32_t result_classid = (classid && *classid) ? *classid :
+ produce_classid();
+
+ /* set classid as out argument */
+ if (classid && !*classid)
+ *classid = result_classid;
snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
- return cgroup_write_node(buf, CLASSID_FILE_NAME, generated_classid);
+ return cgroup_write_node(buf, CLASSID_FILE_NAME, result_classid);
}
static u_int32_t get_classid_from_cgroup(const char *cgroup, const char *subdir)
@@ -154,42 +160,38 @@ populate_classids_with_pids(const char *dir_name_buf, size_t dir_name_buf_len,
u_int32_t get_classid_by_app_id(const char *app_id, int create)
{
- char pkgname[MAX_PATH_LENGTH];
- extract_pkgname(app_id, pkgname, sizeof(pkgname));
- return get_classid_by_pkg_name(pkgname, create);
-}
-
-API u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create)
-{
int ret = 0;
int exists;
u_int32_t classid = RESOURCED_UNKNOWN_CLASSID;
- if (!strcmp(pkg_name, RESOURCED_ALL_APP))
+ if (!strcmp(app_id, RESOURCED_ALL_APP))
return RESOURCED_ALL_APP_CLASSID;
- if (!strcmp(pkg_name, TETHERING_APP_NAME))
+ if (!strcmp(app_id, TETHERING_APP_NAME))
return RESOURCED_TETHERING_APP_CLASSID;
+ if (!strcmp(app_id, RESOURCED_BACKGROUND_APP_NAME))
+ return RESOURCED_FOREGROUND_APP_CLASSID;
+
/* just read */
if (!create)
classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
- pkg_name);
+ app_id);
if (classid != RESOURCED_UNKNOWN_CLASSID)
return classid;
- ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name,
+ ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)app_id,
&exists);
if (ret)
goto handle_error;
if (exists)
classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
- pkg_name);
+ app_id);
else
ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
- (char *)pkg_name, &classid);
+ (char *)app_id, &classid);
if (ret)
goto handle_error;
@@ -201,7 +203,6 @@ API u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create)
return RESOURCED_UNKNOWN_CLASSID;
}
-
int update_classids(void)
{
DIR *dir;
@@ -298,9 +299,9 @@ char *get_app_id_by_classid(const u_int32_t classid, const bool update_state)
return get_app_id_by_classid_local(classid);
}
-API resourced_ret_c make_net_cls_cgroup_with_pid(const int pid, const char *pkg_name)
+API resourced_ret_c make_net_cls_cgroup(const char *pkg_name, u_int32_t classid)
{
- int ret = 0;
+ resourced_ret_c ret = RESOURCED_ERROR_NONE;
int exists = 0;
if (pkg_name == NULL) {
@@ -308,17 +309,44 @@ API resourced_ret_c make_net_cls_cgroup_with_pid(const int pid, const char *pkg_
return RESOURCED_ERROR_INVALID_PARAMETER;
}
- _SD("pkg: %s; pid: %d\n", pkg_name, pid);
-
ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name, &exists);
ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
if (!exists) {
ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name,
- NULL);
+ classid ? &classid : NULL);
ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
}
+ return ret;
+}
+
+API resourced_ret_c place_pids_to_net_cgroup(const int pid, const char *pkg_name)
+{
+ char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
+ snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid);
+
+ if (access(child_buf, F_OK)) {
+ _D("%s of %s is not existed", child_buf, pkg_name);
+ return place_pid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
+ }
- return place_pid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
+ return place_pidtree_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
}
+API resourced_ret_c make_net_cls_cgroup_with_pid(const int pid, const char *pkg_name)
+{
+ resourced_ret_c ret = make_net_cls_cgroup(pkg_name, RESOURCED_UNKNOWN_CLASSID);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret, "Can't create cgroup %s!", pkg_name);
+ _SD("pkg: %s; pid: %d\n", pkg_name, pid);
+ return place_pids_to_net_cgroup(pid, pkg_name);
+}
+
+void create_net_background_cgroup(struct counter_arg *carg)
+{
+ resourced_ret_c ret = make_net_cls_cgroup(RESOURCED_BACKGROUND_APP_NAME,
+ RESOURCED_BACKGROUND_APP_CLASSID);
+ if (ret == RESOURCED_ERROR_NONE)
+ background_apps(carg);
+ else
+ _E("Could not support quota for background application");
+}
diff --git a/src/network/network-dummy.c b/src/network/network-dummy.c
deleted file mode 100644
index e6f0380d..00000000
--- a/src/network/network-dummy.c
+++ /dev/null
@@ -1,150 +0,0 @@
- /*
- * 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.
- *
- */
-
-/*
- * @file network.c
- *
- * @desc Entity for storing applications statistics
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-
-#include "data_usage.h"
-#include "datausage-restriction.h"
-#include "macro.h"
-#include "net-cls-cgroup.h"
-#include "rd-network.h"
-#include "resourced.h"
-
-API network_error_e network_set_option(const network_option_s *options)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_get_option(network_option_s *options)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_make_cgroup_with_pid(const int pid,
- const char *pkg_name)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API u_int32_t network_get_classid_by_pkg_name(const char *pkg_name, int create)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_set_restriction(const char *app_id,
- const network_restriction_s *restriction)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_restriction_foreach(network_restriction_cb restriction_cb,
- void *user_data)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_remove_restriction(const char *app_id)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_remove_restriction_by_iftype(const char *app_id,
- const network_iface_e iftype)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_exclude_restriction(const char *app_id)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_exclude_restriction_by_iftype(
- const char *app_id, const network_iface_e iftype)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_register_activity_cb(network_activity_cb activity_cb)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_join_app_performance(const char *app_id, const pid_t pid)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_update_statistics(void)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_foreach(const network_selection_rule_s *rule,
- network_info_cb info_cb, void *user_data)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_details_foreach(const char *app_id,
- network_selection_rule_s *rule,
- network_info_cb info_cb,
- void *user_data)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_reset(const network_reset_rule_s *rule)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_remove_quota(
- const network_quota_reset_rule_s *rule)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_remove_quota_by_iftype(
- const char *app_id, const network_iface_e iftype)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_set_quota(const char *app_id,
- const network_quota_s *quota)
-{
- return NETWORK_ERROR_NONE;
-}
-
-API network_error_e network_get_restriction_state(const char *pkg_id,
- network_iface_e iftype, network_restriction_state *state)
-{
- *state = NETWORK_RESTRICTION_UNDEFINDED;
- return NETWORK_ERROR_NONE;
-}
diff --git a/src/network/network.c b/src/network/network.c
deleted file mode 100644
index 225e059f..00000000
--- a/src/network/network.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.
- *
- */
-
-/*
- * @file network.c
- *
- * @desc Entity for storing applications statistics
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <stdio.h>
-
-#include "data_usage.h"
-#include "datausage-restriction.h"
-#include "macro.h"
-#include "net-cls-cgroup.h"
-#include "rd-network.h"
-#include "resourced.h"
-
-API network_error_e network_set_option(const network_option_s *options)
-{
- return (network_error_e)set_resourced_options((const resourced_options*)options);
-}
-
-API network_error_e network_get_option(network_option_s *options)
-{
- return (network_error_e)get_resourced_options((resourced_options*)options);
-}
-
-API network_error_e network_make_cgroup_with_pid(const int pid,
- const char *pkg_name)
-{
- return (network_error_e)make_net_cls_cgroup_with_pid(pid, pkg_name);
-}
-
-API u_int32_t network_get_classid_by_pkg_name(const char *pkg_name, int create)
-{
- return (network_error_e)get_classid_by_pkg_name(pkg_name, create);
-}
-
-API network_error_e network_set_restriction(const char *app_id,
- const network_restriction_s *restriction)
-{
- return (network_error_e)set_net_restriction(app_id,
- (const resourced_net_restrictions*)restriction);
-}
-
-API network_error_e network_restriction_foreach(network_restriction_cb restriction_cb,
- void *user_data)
-{
- return (network_error_e)restrictions_foreach((resourced_restriction_cb)restriction_cb, user_data);
-}
-
-API network_error_e network_remove_restriction(const char *app_id)
-{
- return (network_error_e)remove_restriction(app_id);
-}
-
-API network_error_e network_remove_restriction_by_iftype(const char *app_id,
- const network_iface_e iftype)
-{
- return (network_error_e)remove_restriction_by_iftype(app_id, (const resourced_iface_type)iftype);
-}
-
-API network_error_e network_exclude_restriction(const char *app_id)
-{
- return (network_error_e)exclude_restriction(app_id);
-}
-
-API network_error_e network_exclude_restriction_by_iftype(
- const char *app_id, const network_iface_e iftype)
-{
- return (network_error_e)exclude_restriction_by_iftype(
- app_id, (const resourced_iface_type)iftype);
-}
-
-API network_error_e network_register_activity_cb(network_activity_cb activity_cb)
-{
- return (network_error_e)register_net_activity_cb((net_activity_cb)activity_cb);
-}
-
-API network_error_e network_join_app_performance(const char *app_id, const pid_t pid)
-{
- return (network_error_e)join_app_performance(app_id, pid);
-}
-
-API network_error_e network_update_statistics(void)
-{
- return (network_error_e)resourced_update_statistics();
-}
-
-API network_error_e network_foreach(const network_selection_rule_s *rule,
- network_info_cb info_cb, void *user_data)
-{
- return (network_error_e)data_usage_foreach(
- (const data_usage_selection_rule*)rule,
- (data_usage_info_cb)info_cb,
- user_data);
-}
-
-API network_error_e network_details_foreach(const char *app_id,
- network_selection_rule_s *rule,
- network_info_cb info_cb,
- void *user_data)
-{
- return (network_error_e)data_usage_details_foreach(app_id,
- (data_usage_selection_rule*)rule,
- (data_usage_info_cb)info_cb,
- user_data);
-}
-
-API network_error_e network_reset(const network_reset_rule_s *rule)
-{
- return (network_error_e)reset_data_usage((const data_usage_reset_rule*)rule);
-}
-
-API network_error_e network_remove_quota(
- const network_quota_reset_rule_s *rule)
-{
- return (network_error_e)remove_datausage_quota(
- (const struct datausage_quota_reset_rule*)rule);
-}
-
-API network_error_e network_remove_quota_by_iftype(
- const char *app_id, const network_iface_e iftype)
-{
- return (network_error_e)remove_datausage_quota_by_iftype(app_id,
- (const resourced_iface_type)iftype);
-}
-
-API network_error_e network_set_quota(const char *app_id,
- const network_quota_s *quota)
-{
- return (network_error_e)set_datausage_quota(app_id,
- (const data_usage_quota*)quota);
-}
-
-API network_error_e network_get_restriction_state(const char *pkg_id,
- network_iface_e iftype, network_restriction_state *state)
-{
- return (network_error_e)get_restriction_state(pkg_id,
- (const resourced_iface_type)iftype,
- (resourced_restriction_state *)state);
-}
diff --git a/src/network/nf-restriction.c b/src/network/nf-restriction.c
index e2704e92..fc26e88a 100644
--- a/src/network/nf-restriction.c
+++ b/src/network/nf-restriction.c
@@ -34,12 +34,23 @@
#include "netlink-restriction.h"
#include "nfacct-rule.h"
#include "resourced.h"
+#include "restriction-helper.h"
+#include "telephony.h"
#include "trace.h"
static resourced_ret_c apply_net_restriction(struct nfacct_rule *rule,
const int send_limit, const int rcv_limit)
{
- nfacct_rule_jump jump = rule->intend == NFACCT_WARN ? NFACCT_JUMP_ACCEPT :
+ nfacct_rule_jump jump;
+
+ /* block immediately */
+ if (!rcv_limit) { /* for dual nfacct entity for restriction add || !send_limit */
+ return produce_net_rule(rule, 0, 0,
+ NFACCT_ACTION_INSERT, NFACCT_JUMP_REJECT,
+ NFACCT_COUNTER_OUT);
+ }
+
+ jump = rule->intend == NFACCT_WARN ? NFACCT_JUMP_ACCEPT :
NFACCT_JUMP_REJECT;
return produce_net_rule(rule, send_limit, rcv_limit,
@@ -78,11 +89,12 @@ static resourced_ret_c exclude_net_restriction(struct nfacct_rule *rule)
}
resourced_ret_c send_net_restriction(const enum traffic_restriction_type rst_type,
- const u_int32_t classid,
+ const u_int32_t classid, const int quota_id,
const resourced_iface_type iftype,
const int send_limit, const int rcv_limit,
const int snd_warning_threshold,
- const int rcv_warning_threshold)
+ const int rcv_warning_threshold,
+ const char *ifname)
{
int ret;
struct shared_modules_data *m_data = get_shared_modules_data();
@@ -90,9 +102,11 @@ resourced_ret_c send_net_restriction(const enum traffic_restriction_type rst_typ
struct nfacct_rule rule = {
.name = {0},
.ifname = {0},
- 0,
+ .quota_id = quota_id,
};
+ rule.rst_state = convert_to_restriction_state(rst_type);
+
ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL, "Empty shared modules data");
carg = m_data->carg;
@@ -102,10 +116,12 @@ resourced_ret_c send_net_restriction(const enum traffic_restriction_type rst_typ
rule.classid = classid;
rule.iftype = iftype;
rule.carg = carg;
+ rule.roaming = get_current_roaming();
+ STRING_SAVE_COPY(rule.ifname, ifname);
if (rst_type == RST_SET) {
- if (snd_warning_threshold ||
- rcv_warning_threshold) {
+ /* snd_warning_threshold && */
+ if (rcv_warning_threshold) {
rule.intend = NFACCT_WARN;
ret = apply_net_restriction(&rule,
snd_warning_threshold, rcv_warning_threshold);
diff --git a/src/network/nfacct-rule.c b/src/network/nfacct-rule.c
index c5e2355f..1acdde85 100644
--- a/src/network/nfacct-rule.c
+++ b/src/network/nfacct-rule.c
@@ -36,6 +36,7 @@
#include "const.h"
#include "counter.h"
+#include "datausage-common.h"
#include "iface.h"
#include "macro.h"
#include "module-data.h"
@@ -53,21 +54,22 @@
#define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
#define REJECT_RULE " -j REJECT"
#define ACCEPT_RULE " -j ACCEPT"
+#define OUT_RULE "OUTPUT"
+#define IN_RULE "INPUT"
+#define FORWARD_RULE "FORWARD"
/* TODO idea to use the same rule both for BLOCK (REJECT) and WARNING (ACCEPT) */
#define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s"
#define RULE_APP_IN "%s -w %s INPUT -i %s -m cgroup --cgroup %u %s %s"
-#define RULE_IFACE_OUT "%s -w %s OUTPUT -o %s %s -m cgroup ! --cgroup 0 %s"
-#define RULE_IFACE_IN "%s -w %s INPUT -i %s %s -m cgroup ! --cgroup 0 %s"
-#define NFNL_SUBSYS_ACCT 7
+/* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
+
+#define RULE_IFACE_OUT "%s -w %s %s -o %s %s %s"
+#define RULE_IFACE_IN "%s -w %s %s -i %s %s %s"
+
-enum nfnl_acct_flags {
- NFACCT_F_QUOTA_PKTS = (1 << 0),
- NFACCT_F_QUOTA_BYTES = (1 << 1),
- NFACCT_F_OVERQUOTA = (1 << 2), /* can't be set from userspace */
-};
+#define NFNL_SUBSYS_ACCT 7
static void prepare_netlink_msg(struct genl *req, int type, int flag)
{
@@ -161,31 +163,71 @@ static resourced_ret_c nfacct_send_new(struct nfacct_rule *counter)
return send_nfacct_request(counter->carg->sock, &req);
}
-static resourced_ret_c nfacct_send_del(struct nfacct_rule *counter)
+resourced_ret_c nfacct_send_del(struct nfacct_rule *counter)
{
struct genl req;
+#ifdef DEBUG_ENABLED
+ _D("send remove request for %s", counter->name);
+#endif
prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
add_string_attr(&req, counter->name, NFACCT_NAME);
return send_nfacct_request(counter->carg->sock, &req);
}
#define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
-resourced_ret_c nfacct_send_get(struct counter_arg *carg)
+
+static resourced_ret_c internal_nfacct_send_get(struct counter_arg *carg,
+ enum nfnl_acct_msg_types get_type, const char *name,
+ int mask, int filter)
{
struct genl req;
struct nlattr *na;
- prepare_netlink_msg(&req, NFNL_MSG_ACCT_GET_CTRZERO,
- NLM_F_DUMP);
+ int flag = !name ? NLM_F_DUMP : 0;
+ prepare_netlink_msg(&req, get_type,
+ flag);
/* due we don't get counter with quota any where else,
* here we will request just counters by default */
+ if (name)
+ add_string_attr(&req, name, NFACCT_NAME);
+
na = start_nest_attr(&req, NFACCT_FILTER);
- add_uint32_attr(&req, NFACCT_F_QUOTAS,
+ add_uint32_attr(&req, htonl(mask),
NFACCT_FILTER_ATTR_MASK);
- add_uint32_attr(&req, 0, NFACCT_FILTER_ATTR_VALUE);
+ add_uint32_attr(&req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
end_nest_attr(&req, na);
return send_nfacct_request(carg->sock, &req);
}
+resourced_ret_c nfacct_send_get_counters(struct counter_arg *carg, const char *name)
+{
+ /* get and reset countes value */
+ return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
+ NFACCT_F_QUOTAS, 0);
+}
+
+resourced_ret_c nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
+{
+ /* just get counters */
+ return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name, NFACCT_F_QUOTA_BYTES,
+ NFACCT_F_QUOTA_BYTES);
+}
+
+resourced_ret_c nfacct_send_get_all(struct counter_arg *carg)
+{
+ /* get and reset everything, used when quiting */
+ return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL, 0, 0);
+}
+
+resourced_ret_c nfacct_send_get(struct nfacct_rule *rule)
+{
+ if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
+ return nfacct_send_get_quotas(rule->carg, rule->name);
+ else if (rule->intend == NFACCT_COUNTER)
+ return nfacct_send_get_counters(rule->carg, rule->name);
+
+ return RESOURCED_ERROR_INVALID_PARAMETER;
+}
+
resourced_ret_c nfacct_send_initiate(struct counter_arg *carg)
{
struct genl req;
@@ -212,8 +254,11 @@ bool recreate_counter_by_name(char *cnt_name, struct nfacct_rule *cnt)
char *classid_part;
char *io_part;
char *ifname_part;
+ char name[MAX_NAME_LENGTH]; /* parse buffer to avoid cnt_name modification */
+
+ strncpy(name, cnt_name, sizeof(name));
- switch (cnt_name[0]) {
+ switch (name[0]) {
case 'c':
cnt->intend = NFACCT_COUNTER;
break;
@@ -223,11 +268,52 @@ bool recreate_counter_by_name(char *cnt_name, struct nfacct_rule *cnt)
case 'r':
cnt->intend = NFACCT_BLOCK;
break;
+ case 't':
+ cnt->intend = NFACCT_TETH_COUNTER;
+ break;
default:
return false;
}
- io_part = strtok(cnt_name, "_");
+ STRING_SAVE_COPY(cnt->name, cnt_name);
+
+ if (cnt->intend == NFACCT_TETH_COUNTER) {
+ char ifname_buf[MAX_IFACE_LENGTH];
+ int ifname_len;
+ resourced_iface_type iface;
+ /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
+ * it's outgoing traffic, due all tethering is mobile databased */
+ iftype_part = strchr(name, ':');
+ ret_value_msg_if (iftype_part == NULL,
+ false, "Invalid format of the tethering counter %s", name);
+ ifname_len = iftype_part - name - 1;
+ strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
+ ifname_buf[ifname_len] = '\0';
+ iface = get_iftype_by_name(ifname_buf);
+ /* check first part is it datacall */
+ if (iface == RESOURCED_IFACE_DATACALL) {
+ strcpy(cnt->ifname, ifname_buf);
+ cnt->iotype = NFACCT_COUNTER_IN;
+ } else {
+ strcpy(ifname_buf, iftype_part + 1); /* +1, due : symbol and
+ til the end of cnt_name */
+ iface = get_iftype_by_name(ifname_buf);
+ if (iface == RESOURCED_IFACE_DATACALL) {
+ cnt->iotype = NFACCT_COUNTER_OUT;
+ strcpy(cnt->ifname, ifname_buf);
+ }
+ }
+
+ if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
+ _E("cant determine tethering direction %s", name);
+ return false;
+ }
+ cnt->iftype = RESOURCED_IFACE_DATACALL;
+ cnt->classid = RESOURCED_TETHERING_APP_CLASSID;
+ return true;
+ }
+
+ io_part = strtok(name, "_");
if (io_part != NULL)
cnt->iotype = convert_to_iotype(atoi(io_part + 1));
else
@@ -313,10 +399,15 @@ static unsigned int get_args_number(const char *cmd_buf)
return count;
}
-static void wait_for_rule_cmd(struct nfacct_rule *rule, pid_t pid)
+static void wait_for_rule_cmd(pid_t pid)
{
int status;
- pid_t ret_pid = waitpid(pid, &status, 0);
+ pid_t ret_pid;
+ if (!pid) {
+ _D("no need to wait");
+ return;
+ }
+ ret_pid = waitpid(pid, &status, 0);
if (ret_pid < 0)
_D("can't wait for a pid %d %d %s", pid, status, strerror(errno));
}
@@ -396,7 +487,7 @@ static char *choose_iftype_name(struct nfacct_rule *rule)
}
static resourced_ret_c exec_iface_cmd(const char *pattern, const char *cmd,
- const char *nfacct, const char *jump,
+ const char *chain, const char *nfacct, const char *jump,
char *iftype_name, pid_t *pid)
{
char block_buf[MAX_PATH_LENGTH];
@@ -405,9 +496,9 @@ static resourced_ret_c exec_iface_cmd(const char *pattern, const char *cmd,
ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
"Invalid network interface name argument");
- ret = sprintf(block_buf, pattern, IPTABLES, cmd,
+ ret = sprintf(block_buf, pattern, IPTABLES, cmd, chain,
iftype_name, nfacct, jump);
- ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
+ ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_FAIL,
"Not enough buffer");
return exec_iptables_cmd(block_buf, pid);
}
@@ -423,7 +514,7 @@ static resourced_ret_c exec_app_cmd(const char *pattern, const char *cmd,
"Invalid network interface name argument");
ret = sprintf(block_buf, pattern, IPTABLES, cmd,
iftype_name, classid, nfacct, jump);
- ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
+ ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_FAIL,
"Not enough buffer");
return exec_iptables_cmd(block_buf, pid);
}
@@ -440,6 +531,16 @@ static char *get_iptables_cmd(const nfacct_rule_action action)
return "";
}
+static char *get_iptables_chain(const nfacct_rule_direction iotype)
+{
+ if (iotype == NFACCT_COUNTER_IN)
+ return IN_RULE;
+ else if(iotype == NFACCT_COUNTER_OUT)
+ return OUT_RULE;
+
+ return "";
+}
+
static char *get_iptables_jump(const nfacct_rule_jump jump)
{
if (jump == NFACCT_JUMP_ACCEPT)
@@ -473,15 +574,23 @@ static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
* don't use it in case of just block without a limit
* iow, send_limit = 0 and rcv_limit 0 */
if (action != NFACCT_ACTION_DELETE) {
+ ret = nfacct_send_del(rule);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "can't del quota counter");
+
ret = nfacct_send_new(rule);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
"can't set nfacct counter");
+ keep_counter(rule);
}
/* we have a counter, let's key in a rule, drop in case of
* send_limit/rcv_limit */
ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
rule->name);
+ ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, RESOURCED_ERROR_FAIL,
+ "Not enought buffer");
+
ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf,
jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
@@ -490,16 +599,16 @@ static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
rule->classid, set_cmd, jump_cmd);
/* remove in any case */
- if (action != NFACCT_ACTION_APPEND) {
+ if (action == NFACCT_ACTION_DELETE) {
/* TODO here and everywhere should be not just a del,
* here should be get counted value and than
* set new counter with that value, but it's minor issue,
* due it's not clear when actual counters was stored,
* and based on which value settings made such decition */
- wait_for_rule_cmd(rule, pid);
- ret = nfacct_send_del(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set nfacct counter");
+ wait_for_rule_cmd(pid);
+ rule->iptables_rule = nfacct_send_del;
+ set_finalize_flag(rule);
+ nfacct_send_get(rule);
}
}
@@ -509,27 +618,36 @@ static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
rule->quota = send_limit;
generate_counter_name(rule);
if (action != NFACCT_ACTION_DELETE) {
+ ret = nfacct_send_del(rule);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "can't del quota counter");
+
ret = nfacct_send_new(rule);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
"can't set quota counter");
+ keep_counter(rule);
}
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set counter");
-
ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
rule->name);
+ ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, RESOURCED_ERROR_FAIL,
+ "Not enought buffer");
+
ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf,
jump_cmd, rule->classid, choose_iftype_name(rule), &pid);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
RESOURCED_ERROR_FAIL, "Can't set conditional block for engress"
" traffic, for classid %u, cmd %s, j %s",
rule->classid, set_cmd, jump_cmd);
- if (action != NFACCT_ACTION_APPEND) {
- wait_for_rule_cmd(rule, pid);
- ret = nfacct_send_del(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't del nfacct counter");
+ if (action == NFACCT_ACTION_DELETE) {
+ wait_for_rule_cmd(pid);
+ rule->iptables_rule = nfacct_send_del;
+ /* not effective, it's better to replace
+ * set_finalize_flag by set_property,
+ * due keep_counter it necessary only for
+ * setting iptables_rule */
+ set_finalize_flag(rule);
+ nfacct_send_get(rule);
}
}
return RESOURCED_ERROR_NONE;
@@ -548,68 +666,86 @@ static resourced_ret_c produce_iface_rule(struct nfacct_rule *rule,
resourced_ret_c ret;
pid_t pid = 0;
- if (iotype & NFACCT_COUNTER_IN) {
- /* income part */
- rule->quota = rcv_limit;
- rule->iotype = NFACCT_COUNTER_IN;
- generate_counter_name(rule);
+ /* keep one name for all restriction always */
+ rule->iotype = NFACCT_COUNTER_IN;
+ rule->quota = rcv_limit;
+ generate_counter_name(rule);
- if (action != NFACCT_ACTION_DELETE) {
- ret = nfacct_send_new(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set quota counter");
- }
+ if (action != NFACCT_ACTION_DELETE) {
+ /* send delete comman in case of creation,
+ * because nfacct doesn't reset value for nfacct quota
+ * in case of quota existing */
+ ret = nfacct_send_del(rule);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "can't del quota counter");
+ ret = nfacct_send_new(rule);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "can't set quota counter");
+ keep_counter(rule);
+ }
+
+ if (iotype & NFACCT_COUNTER_IN) {
+ /* income part */
ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
NFACCT_NAME_MOD, rule->name);
- ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+ ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, RESOURCED_ERROR_FAIL,
"Not enought buffer");
- ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, nfacct_buf,
- jump_cmd, choose_iftype_name(rule), &pid);
+ ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, get_iptables_chain(rule->iotype),
+ nfacct_buf, jump_cmd, choose_iftype_name(rule), &pid);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
- RESOURCED_ERROR_NONE, "Can't set conditional block for ingress"
+ RESOURCED_ERROR_FAIL, "Can't set conditional block for ingress"
" traffic, for iftype %d, cmd %s, j %s",
rule->iftype, set_cmd, jump_cmd);
- if (action != NFACCT_ACTION_APPEND) {
- wait_for_rule_cmd(rule, pid);
- ret = nfacct_send_del(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set quota counter");
+ /* for tethering */
+ if (rule->intend == NFACCT_WARN || rule->intend == NFACCT_BLOCK) {
+ /* RULE_IFACE_OUT is not a misprint here */
+ wait_for_rule_cmd(pid);
+ ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, FORWARD_RULE, nfacct_buf,
+ jump_cmd, choose_iftype_name(rule), &pid);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
+ RESOURCED_ERROR_FAIL, "Can't set forward rule for ingress"
+ " traffic, for iftype %d, cmd %s, j %s",
+ rule->iftype, set_cmd, jump_cmd);
}
+ /* tethering */
}
if (iotype & NFACCT_COUNTER_OUT) {
/* outcome part */
- rule->iotype = NFACCT_COUNTER_OUT;
rule->quota = send_limit;
- generate_counter_name(rule);
-
- if (action != NFACCT_ACTION_DELETE) {
- ret = nfacct_send_new(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set quota counter");
- }
ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
NFACCT_NAME_MOD, rule->name);
- ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+ ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0, RESOURCED_ERROR_FAIL,
"Not enough buffer");
- ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, nfacct_buf,
+ wait_for_rule_cmd(pid);
+ ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE, nfacct_buf,
jump_cmd, choose_iftype_name(rule), &pid);
ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
RESOURCED_ERROR_FAIL, "Can't set conditional block for "
" engress traffic, for iftype %d, cmd %s, j %s",
rule->iftype, set_cmd, jump_cmd);
-
- if (action != NFACCT_ACTION_APPEND) {
- wait_for_rule_cmd(rule, pid);
- ret = nfacct_send_del(rule);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "can't set quota counter");
+ /* for tethering */
+ if (rule->intend == NFACCT_WARN || rule->intend == NFACCT_BLOCK) {
+ wait_for_rule_cmd(pid);
+ ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, FORWARD_RULE, nfacct_buf,
+ jump_cmd, choose_iftype_name(rule), &pid);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
+ RESOURCED_ERROR_FAIL, "Can't set forward rule for engress"
+ " traffic, for iftype %d, cmd %s, j %s",
+ rule->iftype, set_cmd, jump_cmd);
}
+ /* tethering */
+ }
+ if (action == NFACCT_ACTION_DELETE) {
+ wait_for_rule_cmd(pid);
+ rule->iptables_rule = nfacct_send_del;
+ set_finalize_flag(rule);
+ nfacct_send_get(rule);
}
return RESOURCED_ERROR_NONE;
}
@@ -640,22 +776,21 @@ resourced_ret_c produce_net_rule(struct nfacct_rule *rule,
void generate_counter_name(struct nfacct_rule *counter)
{
char warn_symbol = 'c';
- char *iftype_name = get_iftype_name(counter->iftype);
- ret_msg_if(iftype_name == NULL, "Can't get interface name!");
- STRING_SAVE_COPY(counter->ifname, iftype_name);
+ if (!strlen(counter->ifname)) {
+ char *iftype_name = get_iftype_name(counter->iftype);
+ /* trace counter name, maybe name was already generated */
+ ret_msg_if(iftype_name == NULL,
+ "Can't get interface name for counter %s, iftype %d)!",
+ counter->name, counter->iftype);
+ STRING_SAVE_COPY(counter->ifname, iftype_name);
+ }
if (counter->intend == NFACCT_WARN)
warn_symbol = 'w';
else if (counter->intend == NFACCT_BLOCK)
warn_symbol = 'r';
- if (counter->classid != RESOURCED_ALL_APP_CLASSID)
- snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%d_%s",
+ snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%d_%s",
warn_symbol, counter->iotype, counter->iftype,
counter->classid, counter->ifname);
- else
- snprintf(counter->name, MAX_NAME_LENGTH, "%c%d_%d_%s",
- warn_symbol, counter->iotype, counter->iftype,
- counter->ifname);
-
- }
+}
diff --git a/src/network/notification-mobile.c b/src/network/notification-mobile.c
new file mode 100644
index 00000000..bfcb3353
--- /dev/null
+++ b/src/network/notification-mobile.c
@@ -0,0 +1,204 @@
+/*
+ * 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 notification_mobile.c
+ *
+ * @desc Notification specific functions
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <resourced.h>
+
+#include "edbus-handler.h"
+#include "notification.h"
+#include "trace.h"
+#include "macro.h"
+#include "telephony.h"
+#include "datausage-vconf-common.h"
+
+#define RESTRICTION_ACTIVE "RestrictionActive"
+#define RESTRICTION_WARNING "RestrictionWarning"
+#define B_TO_MB (1024 * 1024)
+
+static int warning_noti_id = 0;
+static int disable_noti_id = 0;
+
+static int *get_noti_id(int type)
+{
+ if (type == WARNING_NOTI)
+ return &warning_noti_id;
+ else if (type == DISABLE_NOTI)
+ return &disable_noti_id;
+ else
+ _E("No matched noti type: %d", type);
+ return NULL;
+}
+
+static int call_datausage_noti(const char *method_name, char *sig, char *pa[])
+{
+ DBusError err;
+ DBusMessage *msg;
+ int ret, ret_val;
+ int i = 0;
+
+ do {
+ msg = dbus_method_sync(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_DATAUSAGE, SYSTEM_POPUP_IFACE_DATAUSAGE, method_name, sig, pa);
+ if (msg)
+ break;
+ _E("Re-try to sync DBUS message, err_count : %d", i);
+ } while (i++ < RETRY_MAX);
+
+ if (!msg) {
+ _E("Failed to sync DBUS message.");
+ return -EBADMSG;
+ }
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
+ if (!ret) {
+ _E("no message : [%s:%s]\n", err.name, err.message);
+ ret_val = -EBADMSG;
+ }
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+
+ return ret_val;
+}
+
+static int clear_datausage_noti(int *id, const char *method_name)
+{
+ char buf[MAX_DEC_SIZE(int)];
+ char *pa[1];
+ int ret;
+
+ ret_value_msg_if (!id || !method_name, -EINVAL, "Invalid param");
+
+ snprintf(buf, sizeof(buf), "%d", *id);
+
+ pa[0] = buf;
+ ret = call_datausage_noti(method_name, "i", pa);
+ if(ret != 0) {
+ _E("clear noti id : %d", *id);
+ *id = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+void check_and_clear_all_noti(void)
+{
+ int *warning_id;
+ int *disable_id;
+
+ /* remove warning noti. */
+ warning_id = get_noti_id(WARNING_NOTI);
+ if (warning_id)
+ clear_datausage_noti(warning_id, WARNING_NOTI_OFF);
+
+ /* remove disable noti. */
+ disable_id = get_noti_id(DISABLE_NOTI);
+ if (disable_id) {
+ clear_datausage_noti(disable_id, DISABLE_NOTI_OFF);
+ restriction_set_status(RESTRICTION_STATE_UNSET);
+ } else
+ _D("No disable noti. to remove");
+}
+
+static int show_restriction_noti(const char *method_name)
+{
+ ret_value_msg_if (!method_name, -EINVAL, "Invalid param");
+
+ return call_datausage_noti(method_name, NULL, NULL);
+}
+
+static int show_restriction_popup(const char *value, data_usage_quota *du_quota)
+{
+ char buf[MAX_DEC_SIZE(int)];
+ char str_val[32];
+ char *pa[4];
+ int ret, retval, quota_limit = -1;
+
+ ret_value_msg_if(!value || !du_quota, -EINVAL, "Invalid param");
+
+ if (restriction_check_limit_status(&retval) < 0)
+ _E("Failed to check limit status");
+
+ if (!retval) {
+ _E("data usage limit is not set");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ quota_limit = (int) du_quota->snd_quota / B_TO_MB;
+
+ ret_value_msg_if(quota_limit <= 0, RESOURCED_ERROR_FAIL, "quota_limit is invalid: %d\n", quota_limit);
+
+ snprintf(str_val, sizeof(str_val), "%s", value);
+ snprintf(buf, sizeof(buf), "%d", quota_limit);
+
+ pa[0] = POPUP_KEY;
+ pa[1] = str_val;
+ pa[2] = POPUP_KEY_LIMIT;
+ pa[3] = buf;
+
+ ret = dbus_method_async(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_DATAUSAGE, SYSTEM_POPUP_IFACE_DATAUSAGE, METHOD_CALL_POPUP, "ssss", pa);
+ if (ret < 0)
+ _E("no message : failed to setting %d", ret);
+ return ret;
+}
+
+void send_restriction_notification(const char *appid, data_usage_quota *du_quota)
+{
+ if (broadcast_edbus_signal(RESOURCED_PATH_NETWORK,
+ RESOURCED_INTERFACE_NETWORK,
+ RESTRICTION_ACTIVE,
+ DBUS_TYPE_STRING,
+ (void *)(&appid)) != RESOURCED_ERROR_NONE) {
+ _E("Failed to send DBUS message.");
+ }
+
+ restriction_set_status(RESTRICTION_STATE_SET);
+
+ _I("Show a network disabled popup & noti.");
+
+ if (warning_noti_id)
+ clear_datausage_noti(&warning_noti_id, WARNING_NOTI_OFF);
+
+ show_restriction_popup(POPUP_VALUE_DISABLED, du_quota);
+ disable_noti_id = show_restriction_noti(DISABLE_NOTI_ON);
+}
+
+void send_restriction_warn_notification(const char *appid, data_usage_quota *du_quota)
+{
+ if (broadcast_edbus_signal(RESOURCED_PATH_NETWORK,
+ RESOURCED_INTERFACE_NETWORK,
+ RESTRICTION_WARNING,
+ DBUS_TYPE_STRING,
+ (void *)(&appid)) != RESOURCED_ERROR_NONE) {
+ _E("Failed to send DBUS message.");
+ }
+
+ _I("Show a network warning notification");
+
+ warning_noti_id = show_restriction_noti(WARNING_NOTI_ON);
+}
diff --git a/src/network/notification.c b/src/network/notification-wearable.c
index f8f96b14..50faf554 100644
--- a/src/network/notification.c
+++ b/src/network/notification-wearable.c
@@ -1,7 +1,7 @@
/*
* resourced
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * 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.
@@ -18,7 +18,7 @@
/*
- * @file notification.c
+ * @file notification_wearable.c
*
* @desc Notification specific functions
*
@@ -32,20 +32,24 @@
#include "notification.h"
#include "trace.h"
#include "macro.h"
-#include "roaming.h"
+#include "telephony.h"
#include "datausage-vconf-common.h"
-#define RESTRICTION_ACTIVE "RestrictionActive"
-#define RESTRICTION_WARNING "RestrictionWarning"
+#define RESTRICTION_ACTIVE "RestrictionActive"
+#define RESTRICTION_WARNING "RestrictionWarning"
-#define NOTI_KEY "_SYSPOPUP_CONTENT_"
-#define NOTI_KEY_LIMIT "_DATAUSAGE_LIMIT_"
-#define NOTI_VALUE_DISABLED "datausage_disabled"
-#define NOTI_VALUE_WARNING "datausage_warning"
+#define NOTI_KEY "_SYSPOPUP_CONTENT_"
+#define NOTI_KEY_LIMIT "_DATAUSAGE_LIMIT_"
+#define NOTI_VALUE_DISABLED "datausage_disabled"
+#define NOTI_VALUE_WARNING "datausage_warning"
+#define METHOD_CALL_POPUP "DatausagePopupLaunch"
-#define METHOD_CALL_POPUP "DatausagePopupLaunch"
+void check_and_clear_all_noti(void)
+{
+
+}
-static int show_restriction_popup(const char *value)
+static int show_restriction_popup(const char *value, data_usage_quota *du_quota)
{
char buf[MAX_DEC_SIZE(int)];
char str_val[32];
@@ -60,9 +64,6 @@ static int show_restriction_popup(const char *value)
return RESOURCED_ERROR_FAIL;
}
- if (restriction_read_quota(&quota_limit) < 0)
- _E("Failed to read a quota value");
-
if (quota_limit <= 0) {
_D("quota_limit is invalid\n");
return RESOURCED_ERROR_FAIL;
@@ -82,7 +83,7 @@ static int show_restriction_popup(const char *value)
return ret;
}
-void send_restriction_notification(const char *appid)
+void send_restriction_notification(const char *appid, data_usage_quota *du_quota)
{
if (broadcast_edbus_signal(RESOURCED_PATH_NETWORK,
RESOURCED_INTERFACE_NETWORK,
@@ -95,10 +96,10 @@ void send_restriction_notification(const char *appid)
restriction_set_status(RESTRICTION_STATE_SET);
_I("Show a network disabled popup");
- show_restriction_popup(NOTI_VALUE_DISABLED);
+ show_restriction_popup(NOTI_VALUE_DISABLED, du_quota);
}
-void send_restriction_warn_notification(const char *appid)
+void send_restriction_warn_notification(const char *appid, data_usage_quota *du_quota)
{
if (broadcast_edbus_signal(RESOURCED_PATH_NETWORK,
RESOURCED_INTERFACE_NETWORK,
@@ -109,6 +110,6 @@ void send_restriction_warn_notification(const char *appid)
}
_I("Show a network warning popup");
- show_restriction_popup(NOTI_VALUE_WARNING);
+ show_restriction_popup(NOTI_VALUE_WARNING, du_quota);
}
diff --git a/src/network/protocol-info.c b/src/network/protocol-info.c
deleted file mode 100644
index e166717c..00000000
--- a/src/network/protocol-info.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.
- *
- */
-
-/*
- * @file protocol-info.c
- *
- * @desc Network protocol entity: now it's only for
- * datacall network interface type
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include <vconf/vconf.h>
-
-#include "macro.h"
-#include "protocol-info.h"
-#include "resourced.h"
-#include "trace.h"
-
-static resourced_hw_net_protocol_type datacall_prot_t = RESOURCED_PROTOCOL_NONE;
-
-static resourced_hw_net_protocol_type _convert_to_resourced_protocol(
- const int prot_type)
-{
- switch (prot_type) {
- case VCONFKEY_TELEPHONY_SVCTYPE_NOSVC:
- return RESOURCED_PROTOCOL_DATACALL_NOSVC;
- case VCONFKEY_TELEPHONY_SVCTYPE_EMERGENCY:
- return RESOURCED_PROTOCOL_DATACALL_EMERGENCY;
- case VCONFKEY_TELEPHONY_SVCTYPE_SEARCH:
- return RESOURCED_PROTOCOL_DATACALL_SEARCH;
- case VCONFKEY_TELEPHONY_SVCTYPE_2G:
- return RESOURCED_PROTOCOL_DATACALL_2G;
- case VCONFKEY_TELEPHONY_SVCTYPE_2_5G:
- return RESOURCED_PROTOCOL_DATACALL_2_5G;
- case VCONFKEY_TELEPHONY_SVCTYPE_2_5G_EDGE:
- return RESOURCED_PROTOCOL_DATACALL_2_5G_EDGE;
- case VCONFKEY_TELEPHONY_SVCTYPE_3G:
- return RESOURCED_PROTOCOL_DATACALL_3G;
- case VCONFKEY_TELEPHONY_SVCTYPE_HSDPA:
- return RESOURCED_PROTOCOL_DATACALL_HSDPA;
- case VCONFKEY_TELEPHONY_SVCTYPE_LTE:
- return RESOURCED_PROTOCOL_DATACALL_LTE;
- case VCONFKEY_TELEPHONY_SVCTYPE_NONE:
- default:
- return RESOURCED_PROTOCOL_NONE;
- }
-}
-
-static resourced_ret_c _get_protocol_type(
- resourced_hw_net_protocol_type *prot_type)
-{
- int ret, status;
-
- ret = vconf_get_int(VCONFKEY_TELEPHONY_SVCTYPE, &status);
- ret_value_msg_if(ret != 0, RESOURCED_ERROR_FAIL,
- "vconf get failed(VCONFKEY_TELEPHONY_SVCTYPE)\n");
- *prot_type = _convert_to_resourced_protocol(status);
- return RESOURCED_ERROR_NONE;
-}
-
-static void _datacall_protocol_type_change_cb(keynode_t *key, void *data)
-{
- int val = vconf_keynode_get_int(key);
-
- _D("key = %s, value = %d(int)\n", vconf_keynode_get_name(key), val);
- datacall_prot_t = _convert_to_resourced_protocol(val);
-}
-
-void init_hw_net_protocol_type(void)
-{
- vconf_notify_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
- _datacall_protocol_type_change_cb, NULL);
- if (_get_protocol_type(&datacall_prot_t) != RESOURCED_ERROR_NONE)
- _E("_get_protocol_type failed\n");
-}
-
-void finalize_hw_net_protocol_type(void)
-{
- vconf_ignore_key_changed(VCONFKEY_TELEPHONY_SVCTYPE,
- _datacall_protocol_type_change_cb);
- datacall_prot_t = RESOURCED_PROTOCOL_NONE;
-}
-
-resourced_hw_net_protocol_type get_hw_net_protocol_type(
- const resourced_iface_type iftype)
-{
- if (iftype == RESOURCED_IFACE_DATACALL)
- return datacall_prot_t;
-
- return RESOURCED_PROTOCOL_NONE;
-}
diff --git a/src/network/reset.c b/src/network/reset.c
index 766a1a07..c2ec0bed 100644
--- a/src/network/reset.c
+++ b/src/network/reset.c
@@ -44,11 +44,14 @@
#define RESET_APP_IFACE "delete from statistics where binpath=? and " \
"iftype=? and time_stamp between ? and ?"
+#define RESET_FIRST_BY_NUMBER "delete from statistics where time_stamp in " \
+ "(select time_stamp from statistics desc limit ?)"
+
/* the following array is strictly ordered
* to find required statement the following code will be used:
* (app ? 1 : 0) | (iftype ? 2 : 0)
*/
-static sqlite3_stmt *reset_stms[4];
+static sqlite3_stmt *reset_stms[5];
#define PREPARE(stm, query) do { \
rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL); \
@@ -73,6 +76,7 @@ static int init_datausage_reset(sqlite3 *db)
PREPARE(reset_stms[1], RESET_APP);
PREPARE(reset_stms[2], RESET_IFACE);
PREPARE(reset_stms[3], RESET_APP_IFACE);
+ PREPARE(reset_stms[4], RESET_FIRST_BY_NUMBER);
initialized = 1;
return rc;
@@ -93,6 +97,33 @@ void finalize_datausage_reset(void)
FINALIZE(reset_stms[i]);
}
+API resourced_ret_c reset_data_usage_first_n_entries(int num)
+{
+ resourced_ret_c result = RESOURCED_ERROR_NONE;
+
+ ret_value_msg_if (!num, RESOURCED_ERROR_INVALID_PARAMETER,
+ "Invalid number of entries");
+ libresourced_db_initialize_once();
+
+ if (init_datausage_reset(resourced_get_database()) != SQLITE_OK) {
+ _D("Failed to initialize data usage reset statements: %s\n",
+ sqlite3_errmsg(resourced_get_database()));
+ return RESOURCED_ERROR_DB_FAILED;
+ }
+ if (sqlite3_bind_int(reset_stms[4], 1, num) != SQLITE_OK) {
+ result = RESOURCED_ERROR_DB_FAILED;
+ goto out;
+ }
+ if (sqlite3_step(reset_stms[4]) != SQLITE_DONE) {
+ _D("Failed to drop collected statistics.");
+ result = RESOURCED_ERROR_DB_FAILED;
+ }
+out:
+ sqlite3_reset(reset_stms[4]);
+ return result;
+}
+
+
API resourced_ret_c reset_data_usage(const data_usage_reset_rule *rule)
{
sqlite3_stmt *stm;
diff --git a/src/network/restriction-handler.c b/src/network/restriction-handler.c
index 2d086645..7d18766c 100644
--- a/src/network/restriction-handler.c
+++ b/src/network/restriction-handler.c
@@ -29,15 +29,19 @@
#include <data_usage.h>
#include <stdlib.h>
#include <net/if.h>
+#include <inttypes.h>
#include "const.h"
+#include "datausage-quota-processing.h"
+#include "datausage-restriction.h"
#include "iface.h"
#include "macro.h"
+#include "module-data.h"
#include "net-cls-cgroup.h"
-#include "trace.h"
-#include "restriction-helper.h"
-#include "datausage-restriction.h"
+#include "notification.h"
#include "restriction-handler.h"
+#include "restriction-helper.h"
+#include "trace.h"
struct restriction_context {
int ifindex;
@@ -101,6 +105,25 @@ struct apply_param
enum restriction_apply_type apply_type;
};
+static bool check_current_imsi_for_restriction(resourced_iface_type iftype,
+ int quota_id)
+{
+ data_usage_quota du_quota = {0};
+ resourced_ret_c ret;
+
+ if (iftype != RESOURCED_IFACE_DATACALL)
+ return false;
+
+ ret = get_quota_by_id(quota_id, &du_quota);
+ if (ret == RESOURCED_ERROR_NONE && du_quota.imsi) {
+ const char *imsi_hash = get_imsi_hash(get_current_modem_imsi());
+ _SD("current imsi %s", imsi_hash);
+ _SD("restrictions imsi %s", du_quota.imsi);
+ return imsi_hash && strcmp(du_quota.imsi, imsi_hash);
+ }
+ return false;
+}
+
static void _reset_restrictions_iter(gpointer data, gpointer user_data)
{
resourced_restriction_info *arg = (resourced_restriction_info *)data;
@@ -118,9 +141,44 @@ static void _reset_restrictions_iter(gpointer data, gpointer user_data)
rst.rcv_limit = arg->rcv_limit;
rst.roaming = arg->roaming;
- if (param->apply_type == KEEP_AS_IS)
+ if (param->apply_type == KEEP_AS_IS) {
+ data_usage_quota du_quota = {0};
+
+ if (check_current_imsi_for_restriction(arg->iftype, arg->quota_id)) {
+ _D("It's restriction for another SIM");
+ return;
+ }
rst_type = convert_to_restriction_type(arg->rst_state);
- else if (param->apply_type == UNSET)
+
+ get_quota_by_id(arg->quota_id, &du_quota);
+
+ if (du_quota.quota_type == RESOURCED_STATE_BACKGROUND) {
+ struct shared_modules_data *m_data;
+ struct counter_arg *carg;
+
+ m_data = get_shared_modules_data();
+ ret_msg_if(m_data == NULL, "Can't get module data!");
+
+ carg = m_data->carg;
+ ret_msg_if(carg == NULL, "Cant' get counter arg!");
+
+ create_net_background_cgroup(carg);
+ }
+
+ /* !rst.send_limit || is needed in dual counter model */
+ if (arg->quota_id && !rst.rcv_limit) {
+ _D("quota rcv: % " PRId64 ", send: % " PRId64 " ", du_quota.rcv_quota, du_quota.snd_quota);
+
+ send_restriction_notification(arg->app_id, &du_quota);
+ } else if(arg->quota_id && rst.rcv_warning_limit) {
+ get_quota_by_id(arg->quota_id, &du_quota);
+ _D("quota rcv: % " PRId64 ", send: % " PRId64 " ", du_quota.rcv_quota, du_quota.snd_quota);
+
+ send_restriction_warn_notification(arg->app_id, &du_quota);
+ }
+
+ /* here we need to request sync get/update of restriction */
+ } else if (param->apply_type == UNSET)
rst_type = RST_UNSET;
else
rst_type = RST_UNDEFINDED;
@@ -128,7 +186,7 @@ static void _reset_restrictions_iter(gpointer data, gpointer user_data)
app_classid = get_classid_by_app_id(arg->app_id, false);
error_code = process_kernel_restriction(app_classid,
- &rst, rst_type);
+ &rst, rst_type, arg->quota_id);
ret_msg_if(error_code != RESOURCED_ERROR_NONE,
"restriction type %d failed, error %d\n", rst_type,
@@ -210,24 +268,7 @@ static void handle_on_iface_down(const int ifindex)
}
_reset_restrictions(context.restrictions);
_free_reset_restrictions(context.restrictions);
-}
-
-static resourced_cb_ret roaming_restrictions_iter(
- const resourced_restriction_info *info, void *user_data)
-{
- struct apply_param param = {.apply_type = KEEP_AS_IS};
- _reset_restrictions_iter((gpointer)info, &param);
- return RESOURCED_CONTINUE;
-}
-
-static void handle_roaming_change(void)
-{
- restrictions_foreach(roaming_restrictions_iter, NULL);
-}
-
-roaming_cb get_roaming_restriction_cb(void)
-{
- return handle_roaming_change;
+ check_and_clear_all_noti();
}
iface_callback *create_restriction_callback(void)
diff --git a/src/network/restriction-helper.c b/src/network/restriction-helper.c
index 609b8c07..5edc7186 100644
--- a/src/network/restriction-helper.c
+++ b/src/network/restriction-helper.c
@@ -31,10 +31,9 @@
resourced_iface_type get_store_iftype(const u_int32_t app_classid,
const resourced_iface_type iftype)
{
- /* We need to put RESOURCED_IFACE_ALL type into the database,
- in case of the "tethering" because it with no iftype */
+ /* in general tethering is based on datacall interface */
return (app_classid == RESOURCED_TETHERING_APP_CLASSID) ?
- RESOURCED_IFACE_ALL : iftype;
+ RESOURCED_IFACE_DATACALL : iftype;
}
resourced_restriction_state convert_to_restriction_state(
diff --git a/src/network/restriction-local.c b/src/network/restriction-local.c
index 6356300f..3388cfee 100644
--- a/src/network/restriction-local.c
+++ b/src/network/restriction-local.c
@@ -35,22 +35,26 @@
#include "init.h"
#include "restriction-helper.h"
#include "datausage-restriction.h"
-#include "roaming.h"
+#include "telephony.h"
#include "storage.h"
#include "trace.h"
#include "tethering-restriction.h"
#define SET_NET_RESTRICTIONS "REPLACE INTO restrictions " \
"(binpath, rcv_limit, send_limit, iftype, rst_state, "\
- " quota_id, roaming) " \
- "VALUES (?, ?, ?, ?, ?, ?, ?)"
+ " quota_id, roaming, ifname) " \
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
#define GET_NET_RESTRICTION "SELECT rcv_limit, send_limit, " \
- " rst_state, quota_id FROM restrictions " \
- "WHERE binpath = ? AND iftype = ?"
+ " rst_state, roaming, quota_id FROM restrictions " \
+ "WHERE binpath = ? AND iftype = ? AND ifname = ?"
+#define GET_NET_RESTRICTION_BY_QUOTA "SELECT rcv_limit, send_limit, " \
+ " rst_state, roaming, ifname FROM restrictions " \
+ "WHERE binpath = ? AND iftype = ? AND quota_id = ?"
+
#define RESET_RESTRICTIONS "DELETE FROM restrictions " \
- "WHERE binpath=? AND iftype=?"
+ "WHERE binpath=? AND iftype=? AND ifname = ? AND quota_id = ?"
static sqlite3_stmt *update_rst_stm;
static sqlite3_stmt *reset_rst_stm;
@@ -73,14 +77,23 @@ handle_error:
}
static resourced_ret_c reset_restriction_db(const char *app_id,
- const resourced_iface_type iftype)
+ const resourced_iface_type iftype,
+ const char *ifname,
+ const int quota_id)
{
resourced_ret_c error_code = init_reset_rst();
ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
+ _D("app_id %s",app_id);
+ _D("iftype %d", iftype);
+ _D("ifname %s", ifname);
+ _D("quota_id %d", quota_id);
+
DB_ACTION(sqlite3_bind_text(reset_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
DB_ACTION(sqlite3_bind_int(reset_rst_stm, 2, iftype));
+ DB_ACTION(sqlite3_bind_text(reset_rst_stm, 3, ifname, -1, SQLITE_TRANSIENT));
+ DB_ACTION(sqlite3_bind_int(reset_rst_stm, 4, quota_id));
if (sqlite3_step(reset_rst_stm) != SQLITE_DONE)
error_code = RESOURCED_ERROR_DB_FAILED;
@@ -116,14 +129,10 @@ resourced_ret_c update_restriction_db(
const int rcv_limit, const int snd_limit,
const resourced_restriction_state rst_state,
const int quota_id,
- const resourced_roaming_type roaming)
+ const resourced_roaming_type roaming,
+ const char *ifname)
{
- resourced_ret_c error_code = RESOURCED_ERROR_NONE;
-
- if (rst_state == RESOURCED_RESTRICTION_REMOVED)
- return reset_restriction_db(app_id, iftype);
-
- error_code = init_update_rest_stmt();
+ resourced_ret_c error_code = init_update_rest_stmt();
ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
DB_ACTION(sqlite3_bind_text(update_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
@@ -133,6 +142,7 @@ resourced_ret_c update_restriction_db(
DB_ACTION(sqlite3_bind_int(update_rst_stm, 5, rst_state));
DB_ACTION(sqlite3_bind_int(update_rst_stm, 6, quota_id));
DB_ACTION(sqlite3_bind_int(update_rst_stm, 7, roaming));
+ DB_ACTION(sqlite3_bind_text(update_rst_stm, 8, ifname, -1, SQLITE_TRANSIENT));
if (sqlite3_step(update_rst_stm) != SQLITE_DONE)
error_code = RESOURCED_ERROR_DB_FAILED;
@@ -147,14 +157,25 @@ handle_error:
return error_code;
}
+/**
+ * Populate restriction info
+ * @param app_id mandatory argument
+ * @param iftype mandatory
+ * @param rst - restriction to fill,
+ * if user specified ifname in it
+ * select will be by ifname
+ * vice versa, if quota_id was specified we are looking ifname
+ * in this case user should release ifname if it's no more needed.
+ * */
resourced_ret_c get_restriction_info(const char *app_id,
- const resourced_iface_type iftype,
+ const resourced_iface_type iftype,
resourced_restriction_info *rst)
{
int rc;
resourced_ret_c error_code = RESOURCED_ERROR_NONE;
- int quota_id = 0;
- sqlite3_stmt *stm = NULL;
+ static sqlite3_stmt *stm_ifname;
+ static sqlite3_stmt *stm_quota;
+ sqlite3_stmt *stm = 0;
ret_value_msg_if(rst == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
"Please provide valid restriction argument!");
@@ -162,13 +183,32 @@ resourced_ret_c get_restriction_info(const char *app_id,
ret_value_msg_if(app_id == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
"Please provide valid app_id argument!");
- _SD("%s, %d", app_id, iftype);
+ _SD("app_id: %s, iftype: %d, ifname: %s, quota_id: %d ",
+ app_id, iftype, rst->ifname, rst->quota_id);
- DB_ACTION(sqlite3_prepare_v2
- (resourced_get_database(), GET_NET_RESTRICTION, -1, &stm, NULL));
+ if (rst->ifname && strlen(rst->ifname)) {
+ if (stm_ifname == NULL) { /* lazy initialization of stm */
+ DB_ACTION(sqlite3_prepare_v2(
+ resourced_get_database(), GET_NET_RESTRICTION, -1,
+ &stm_ifname, NULL));
+ }
+ stm = stm_ifname;
+ } else if (rst->quota_id) {
+ if (stm_quota == NULL) { /* lazy initialization of stm_quota */
+ DB_ACTION(sqlite3_prepare_v2(
+ resourced_get_database(), GET_NET_RESTRICTION_BY_QUOTA,
+ -1, &stm_quota, NULL));
+ }
+ stm = stm_quota;
+ } else
+ return RESOURCED_ERROR_INVALID_PARAMETER;
DB_ACTION(sqlite3_bind_text(stm, 1, app_id, -1, SQLITE_TRANSIENT));
DB_ACTION(sqlite3_bind_int(stm, 2, iftype));
+ if (rst->ifname && strlen(rst->ifname))
+ DB_ACTION(sqlite3_bind_text(stm, 3, rst->ifname, -1, SQLITE_TRANSIENT));
+ else if (rst->quota_id)
+ DB_ACTION(sqlite3_bind_int(stm, 3, rst->quota_id));
do {
rc = sqlite3_step(stm);
@@ -177,7 +217,12 @@ resourced_ret_c get_restriction_info(const char *app_id,
rst->rcv_limit = sqlite3_column_int(stm, 0);
rst->send_limit = sqlite3_column_int64(stm, 1);
rst->rst_state = sqlite3_column_int(stm, 2);
- rst->quota_id = sqlite3_column_int(stm, 3);
+ rst->roaming = sqlite3_column_int(stm, 3);
+ if (rst->ifname && strlen(rst->ifname))
+ rst->quota_id = sqlite3_column_int(stm, 4);
+ else if (rst->quota_id)
+ rst->ifname = strdup((char *)sqlite3_column_text(
+ stm, 4));
break;
case SQLITE_DONE:
@@ -188,19 +233,27 @@ resourced_ret_c get_restriction_info(const char *app_id,
goto handle_error;
}
} while (rc == SQLITE_ROW);
+ sqlite3_reset(stm);
- _D("%d", quota_id);
+ _D("quota_id: %d, if_name: %s", rst->quota_id, rst->ifname);
+
+ return RESOURCED_ERROR_NONE;
handle_error:
- if (stm)
- sqlite3_finalize(stm);
+ if (stm == stm_ifname) {
+ sqlite3_finalize(stm_ifname);
+ stm_ifname = 0;
+ } else if (stm == stm_quota) {
+ sqlite3_finalize(stm_quota);
+ stm_quota = 0;
+ }
if (error_code == RESOURCED_ERROR_DB_FAILED)
- _E("Failed to get network restriction's quota id: %s\n",
+ _E("Failed to fill network restriction's: %s\n",
sqlite3_errmsg(resourced_get_database()));
- return quota_id;
+ return error_code;
}
static bool check_roaming(const resourced_net_restrictions *rst)
@@ -209,7 +262,7 @@ static bool check_roaming(const resourced_net_restrictions *rst)
ret_value_msg_if(rst == NULL, false,
"Invalid net_restriction pointer, please provide valid argument");
- roaming = get_roaming();
+ roaming = get_current_roaming();
_D("roaming %d rst->roaming %d", roaming, rst->roaming);
if (roaming == RESOURCED_ROAMING_UNKNOWN ||
rst->roaming == RESOURCED_ROAMING_UNKNOWN) {
@@ -232,7 +285,8 @@ static void process_net_block_state(const enum
resourced_ret_c process_kernel_restriction(
const u_int32_t classid,
const resourced_net_restrictions *rst,
- const enum traffic_restriction_type rst_type)
+ const enum traffic_restriction_type rst_type,
+ const int quota_id)
{
int ret = RESOURCED_ERROR_NONE;
@@ -249,17 +303,23 @@ resourced_ret_c process_kernel_restriction(
/* TODO check, and think how to implement it
* in unified way, maybe also block FORWARD chain in
* send_net_restriction */
- if (classid == RESOURCED_ALL_APP_CLASSID ||
- classid == RESOURCED_TETHERING_APP_CLASSID)
+ if ((classid == RESOURCED_ALL_APP_CLASSID ||
+ classid == RESOURCED_TETHERING_APP_CLASSID) &&
+ /* apply it now if we'll block now in case of send_limit
+ * rcv_limit 0, or when will block noti come */
+ ((rst_type == RST_UNSET || rst_type == RST_EXCLUDE) ||
+ (rst_type == RST_SET && (!rst->send_limit || !rst->rcv_limit))))
ret = apply_tethering_restriction(rst_type);
+
if (classid != RESOURCED_TETHERING_APP_CLASSID &&
ret == RESOURCED_ERROR_NONE)
- ret = send_net_restriction(rst_type, classid,
+ ret = send_net_restriction(rst_type, classid, quota_id,
rst->iftype,
rst->send_limit,
rst->rcv_limit,
rst->snd_warning_limit,
- rst->rcv_warning_limit);
+ rst->rcv_warning_limit,
+ rst->ifname);
ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
"Restriction, type %d falied, return code %d\n",
rst_type, ret);
@@ -270,7 +330,8 @@ resourced_ret_c process_kernel_restriction(
resourced_ret_c proc_keep_restriction(
const char *app_id, const int quota_id,
const resourced_net_restrictions *rst,
- const enum traffic_restriction_type rst_type)
+ const enum traffic_restriction_type rst_type,
+ bool skip_kernel_op)
{
u_int32_t app_classid = 0;
resourced_iface_type store_iftype;
@@ -280,41 +341,84 @@ resourced_ret_c proc_keep_restriction(
RESOURCED_ERROR_INVALID_PARAMETER,
"Invalid restriction arguments\n");
- app_classid = get_classid_by_app_id(app_id, rst_type != RST_UNSET);
- ret = process_kernel_restriction(app_classid, rst, rst_type);
- ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
- "Can't keep restriction.");
+ if (rst->rs_type == RESOURCED_STATE_BACKGROUND)
+ app_classid = RESOURCED_BACKGROUND_APP_CLASSID;
+ else
+ app_classid = get_classid_by_app_id(app_id, rst_type != RST_UNSET);
+ if (!skip_kernel_op) {
+ ret = process_kernel_restriction(app_classid, rst, rst_type, quota_id);
+ ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+ "Can't keep restriction.");
+ }
store_iftype = get_store_iftype(app_classid, rst->iftype);
rst_state = convert_to_restriction_state(rst_type);
- _SD("restriction: app_id %s, iftype %d, state %d, type %d\n", app_id,
- store_iftype, rst_state, rst_type);
+ _SD("restriction: app_id %s, classid %d, iftype %d, state %d, type %d, "\
+ "imsi %s, rs_type %d\n", app_id, app_classid,
+ store_iftype, rst_state, rst_type, rst->ifname, rst->rs_type);
if (!strcmp(app_id, RESOURCED_ALL_APP) &&
rst->iftype == RESOURCED_IFACE_ALL)
process_net_block_state(rst_type);
- return update_restriction_db(app_id, store_iftype,
- rst->rcv_limit, rst->send_limit,
- rst_state, quota_id, rst->roaming);
+ /* in case of SET/EXCLUDE just update state in db, otherwise remove fro
+ * db */
+ if (rst_type == RST_UNSET)
+ ret = reset_restriction_db(app_id, store_iftype, rst->ifname,
+ quota_id);
+ else
+ ret = update_restriction_db(app_id, store_iftype,
+ rst->rcv_limit, rst->send_limit,
+ rst_state, quota_id, rst->roaming,
+ rst->ifname);
+
+ return ret;
}
resourced_ret_c remove_restriction_local(const char *app_id,
- const resourced_iface_type iftype)
+ const resourced_iface_type iftype,
+ const int quota_id,
+ const char *imsi_hash,
+ const resourced_state_t ground)
{
- resourced_net_restrictions rst = { 0 };
+ resourced_net_restrictions rst = { .iftype = iftype };
+ resourced_restriction_info rst_info = { .iftype = iftype, .quota_id = quota_id };
+
+ bool skip_kernel_op = check_event_in_current_modem(imsi_hash, iftype);
+ /* getting ifname by iftype form none persistent
+ * ifaces list is not so good idea,
+ * for example, user could delete applied quota,
+ * right after reboot, when ifnames is not yet initialized */
+ resourced_ret_c ret = get_restriction_info(app_id, iftype, &rst_info);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _D("Can't get restriction info: app_id %s, iftype %d, quota_id %d",
+ app_id, iftype, quota_id);
+ goto release_ifname;
+ }
+ rst.ifname = (char *)rst_info.ifname;
+ rst.rs_type = ground;
+ ret = proc_keep_restriction(app_id, quota_id, &rst,
+ RST_UNSET, skip_kernel_op);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _D("Can't keep restriction");
+ }
- rst.iftype = iftype;
- return proc_keep_restriction(app_id, NONE_QUOTA_ID, &rst,
- RST_UNSET);
+release_ifname:
+ if(rst_info.ifname)
+ free((char *)rst_info.ifname);
+ return ret;
}
resourced_ret_c exclude_restriction_local(const char *app_id,
const int quota_id,
- const resourced_iface_type iftype)
+ const resourced_iface_type iftype,
+ const char *imsi_hash)
{
resourced_net_restrictions rst = { 0 };
+ bool skip_kernel_op = check_event_in_current_modem(imsi_hash, iftype);
rst.iftype = iftype;
- return proc_keep_restriction(app_id, quota_id, &rst, RST_EXCLUDE);
+ rst.ifname = get_iftype_name(rst.iftype);
+ return proc_keep_restriction(app_id, quota_id, &rst, RST_EXCLUDE,
+ skip_kernel_op);
}
diff --git a/src/network/restriction.c b/src/network/restriction.c
index ffd0ff3e..18995c6b 100644
--- a/src/network/restriction.c
+++ b/src/network/restriction.c
@@ -25,9 +25,7 @@
#include <sqlite3.h>
#include <resourced.h>
#include <data_usage.h>
-#include <rd-network.h>
-#include "cgroup.h" /*get_classid_by_pkg_name */
#include "const.h"
#include "database.h"
#include "datausage-restriction.h"
diff --git a/src/network/roaming.c b/src/network/roaming.c
deleted file mode 100644
index 6152200f..00000000
--- a/src/network/roaming.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.
- *
- */
-
-/*
- *
- * @file roaming.c
- *
- * @desc Roaming persistent object. Due roaming changes not so often we can keep it in
- * our memory and handle roaming changes.
- * In this file we keep roaming state in global variable and change it in callback.
- */
-
-#include <glib.h>
-#include <telephony_network.h>
-
-#include "roaming.h"
-#include "trace.h"
-#include "macro.h"
-
-static resourced_roaming_type roaming_state;
-
-/* for avoiding dependency in this file */
-
-static GSList *roaming_callbacks;
-
-static void invoke_roaming_callbacks(void)
-{
- GSList *func_iter = NULL;
- gslist_for_each_item(func_iter, roaming_callbacks) {
- if (func_iter && func_iter->data)
- ((roaming_cb)func_iter->data)();
- }
-}
-
-void regist_roaming_cb(roaming_cb cb)
-{
- roaming_callbacks = g_slist_prepend(roaming_callbacks, cb);
-}
-
-static void on_roaming_change(bool new_roaming,
- void UNUSED *user_data)
-{
- _D("Roaming is changed %d", (int)new_roaming);
- roaming_state = new_roaming ? RESOURCED_ROAMING_ENABLE : RESOURCED_ROAMING_DISABLE;
- invoke_roaming_callbacks();
-}
-
-/**
- * @brief Get initial value for roaming and sets callback for handling roaming change
- */
-static void init_roaming_state(void)
-{
- bool roaming = false;
-
- if (network_info_set_roaming_state_changed_cb(on_roaming_change,
- NULL) != NETWORK_INFO_ERROR_NONE)
- _E("Can not register callback for handle roaming changes.");
-
- if (network_info_is_roaming(&roaming) != NETWORK_INFO_ERROR_NONE)
- _E("Failed to get initial roaming state!");
-
- roaming_state = roaming ?
- RESOURCED_ROAMING_ENABLE : RESOURCED_ROAMING_DISABLE;
-}
-
-resourced_roaming_type get_roaming(void)
-{
- execute_once {
- init_roaming_state();
- }
- return roaming_state;
-}
-
diff --git a/src/network/specific-trace.c b/src/network/specific-trace.c
index f1d54d1c..1fd2c0e3 100644
--- a/src/network/specific-trace.c
+++ b/src/network/specific-trace.c
@@ -46,12 +46,12 @@ gboolean print_appstat(gpointer key, gpointer value,
return TRUE; /*stop printing*/
}
- _SD("appid %s, pid %d, rcv %u, snd %u, classid %u, iftype %d, ifname %s," \
- " is_roaming %d",
- appstat->application_id, appstat->pid, appstat->rcv_count,
+ _SD("appid %s, rcv %u, snd %u, classid %u, iftype %d, ifname %s," \
+ " is_roaming %d, ground %d",
+ appstat->application_id, appstat->rcv_count,
appstat->snd_count, (u_int32_t)composite_key->classid,
composite_key->iftype, composite_key->ifname,
- appstat->is_roaming);
+ appstat->is_roaming, appstat->ground);
return FALSE;
}
diff --git a/src/network/storage.c b/src/network/storage.c
index f0c67da9..c025fe4f 100644
--- a/src/network/storage.c
+++ b/src/network/storage.c
@@ -38,14 +38,15 @@
#include <unistd.h>
#include "const.h"
-#include "iface.h"
#include "database.h"
#include "datausage-quota-processing.h"
+#include "db-guard.h"
+#include "iface.h"
#include "macro.h"
-#include "protocol-info.h"
-#include "storage.h"
#include "specific-trace.h"
+#include "storage.h"
#include "trace.h"
+#include "telephony.h"
static sqlite3_stmt *update_statistics_query;
static sqlite3_stmt *update_iface_query;
@@ -54,13 +55,15 @@ enum { read_until_null = -1 };
static void handle_on_iface(const int ifindex, resourced_option_state state)
{
- _D("Handling network interface %d, %d", ifindex, state);
-
+ resourced_iface_type iftype;
if (!update_iface_query) {
_E("Uninitialized statement");
return;
}
- sqlite3_bind_int(update_iface_query, 1, get_iftype(ifindex));
+ iftype = get_iftype(ifindex);
+ _D("Handling network interface ifindex:%d, state: %d, iftype: %d",
+ ifindex, state, iftype);
+ sqlite3_bind_int(update_iface_query, 1, iftype);
sqlite3_bind_int(update_iface_query, 2, state);
if (sqlite3_step(update_iface_query) != SQLITE_DONE)
@@ -90,8 +93,9 @@ static int init_update_statistics_query(sqlite3 *db)
rc = sqlite3_prepare_v2(db,
"insert into statistics " \
"(binpath, received, sent, time_stamp, " \
- "iftype, is_roaming, hw_net_protocol_type, ifname) " \
- "values (?, ?, ?, ?, ?, ?, ?, ?)",
+ "iftype, is_roaming, hw_net_protocol_type, " \
+ "ifname, imsi, ground) " \
+ "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
read_until_null, &update_statistics_query, NULL);
if (rc != SQLITE_OK) {
@@ -128,7 +132,7 @@ static gboolean store_application_stat(gpointer key, gpointer value,
struct classid_iftype_key *stat_key = (struct classid_iftype_key *)key;
time_t *last_touch_time = (time_t *)userdata;
resourced_hw_net_protocol_type hw_net_protocol_type =
- get_hw_net_protocol_type(stat_key->iftype);
+ get_current_protocol(stat_key->iftype);
if (!update_statistics_query) {
_E("Uninitialized statement");
@@ -174,6 +178,18 @@ static gboolean store_application_stat(gpointer key, gpointer value,
_SE("Can not bind ifname: %s", stat_key->ifname);
return FALSE;
}
+ if (sqlite3_bind_text(update_statistics_query, 9,
+ get_imsi_hash(stat_key->imsi), read_until_null,
+ SQLITE_STATIC) != SQLITE_OK) {
+ _SE("Can not bind imsi: %s", stat_key->imsi);
+ return FALSE;
+ }
+ if (sqlite3_bind_int(update_statistics_query, 10,
+ (int)stat->ground) != SQLITE_OK) {
+ _E("Can not bind applicaton background type: %d",
+ (int)stat->ground);
+ return FALSE;
+ }
/*we want to reuse tree*/
stat->rcv_count = 0;
@@ -185,37 +201,35 @@ static gboolean store_application_stat(gpointer key, gpointer value,
return FALSE;
}
-int store_result(struct application_stat_tree *stats, int flush_period)
+resourced_ret_c store_result(struct application_stat_tree *stats)
{
time_t current_time;
+ pthread_rwlock_rdlock(&stats->guard);
+ WALK_TREE(stats->tree, print_appstat);
+ pthread_rwlock_unlock(&stats->guard);
+
+ if (init_update_statistics_query(resourced_get_database()) != SQLITE_OK) {
+ _D("Failed to initialize data usage quota statements: %s\n",
+ sqlite3_errmsg(resourced_get_database()));
+ return RESOURCED_ERROR_FAIL; /* Do not iterate and free results */
+ }
+
time(&current_time);
+ stats->last_touch_time = current_time;
+
+ /* it's reader only, we don't modify tree, don't reduce it,
+ * due we want to reuse it in next iteration */
+ pthread_rwlock_rdlock(&stats->guard);
+ g_tree_foreach((GTree *) stats->tree,
+ store_application_stat,
+ &stats->last_touch_time);
+
+ pthread_rwlock_unlock(&stats->guard);
+ flush_quota_table();
+ change_db_entries_num_num(g_tree_nnodes((GTree *)stats->tree));
- if (current_time - stats->last_touch_time >= flush_period) {
-
- pthread_rwlock_rdlock(&stats->guard);
- WALK_TREE(stats->tree, print_appstat);
- pthread_rwlock_unlock(&stats->guard);
-
- if (init_update_statistics_query(resourced_get_database()) != SQLITE_OK) {
- _D("Failed to initialize data usage quota statements: %s\n",
- sqlite3_errmsg(resourced_get_database()));
- return 0; /* Do not iterate and free results */
- }
-
- /* it's reader only, we don't modify tree, don't reduce it,
- * due we want to reuse it in next iteration */
- pthread_rwlock_rdlock(&stats->guard);
- g_tree_foreach((GTree *) stats->tree,
- store_application_stat,
- &stats->last_touch_time);
- pthread_rwlock_unlock(&stats->guard);
- flush_quota_table();
- time(&current_time);
- stats->last_touch_time = current_time;
- return 1;
- }
- return 0;
+ return RESOURCED_ERROR_NONE;
}
void finalize_storage_stm(void)
diff --git a/src/network/telephony.c b/src/network/telephony.c
new file mode 100644
index 00000000..61cadf0b
--- /dev/null
+++ b/src/network/telephony.c
@@ -0,0 +1,625 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 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 telephony.c
+ *
+ * @desc Roaming persistent object. Due roaming changes not so often we can keep it in
+ * our memory and handle roaming changes.
+ * In this file we keep roaming state in global variable.
+ */
+
+#include <glib.h>
+#include <openssl/sha.h>
+#include <stdbool.h>
+#include <vconf/vconf.h>
+#include <vconf/vconf-internal-telephony-keys.h>
+#include <TelSim.h>
+
+#include "config.h"
+#include "const.h"
+#include "edbus-handler.h"
+#include "iface.h"
+#include "macro.h"
+#include "telephony.h"
+#include "trace.h"
+
+/**
+ * @brief Definition for the telephony service name.
+ */
+#define DBUS_TELEPHONY_SERVICE "org.tizen.telephony"
+
+#define DBUS_TELEPHONY_SERVICE_MANAGER DBUS_TELEPHONY_SERVICE".Manager"
+#define DBUS_TELEPHONY_SERVICE_NETWORK DBUS_TELEPHONY_SERVICE".Network"
+#define DBUS_TELEPHONY_SIM_INTERFACE DBUS_TELEPHONY_SERVICE".Sim"
+
+
+/**
+ * @brief Definition for the telephony object path.
+ */
+#define DBUS_TELEPHONY_DEFAULT_PATH "/org/tizen/telephony"
+
+#define DBUS_TELEPHONY_GET_MODEMS "GetModems"
+#define DBUS_TELEPHONY_PROPERTIES_CHANGED "PropertiesChanged"
+#define DBUS_TELEPHONY_ROAMING_STATUS "roaming_status"
+#define DBUS_TELEPHONY_SERVICE_TYPE "service_type"
+#define DBUS_TELEPHONY_GET "Get"
+#define DBUS_TELEPHONY_GET_IMSI "GetIMSI"
+#define DBUS_FREEDESKTOP_PROPERTIES "org.freedesktop.DBus.Properties"
+#define DBUS_TELEPHONY_STATUS "Status"
+
+/**
+ * @brief vconf value for checking active modem
+ * copied from vconfkey-internal
+ */
+#define DEFAULT_DATA_SERVICE_SIM1 0
+#define DEFAULT_DATA_SERVICE_SIM2 1
+#define SIM_SLOT_SINGLE 1
+#define IMSI_LENGTH 16
+
+struct modem_state {
+ char *name;
+ bool roaming;
+ char *path;
+ char *imsi; /* International mobile subscriber identity, to identify SIM card */
+ /* such model will be if we'll have ability to make 2 connection by 2 sim
+ * card simultaneously, but for Kiran the "Dual SIM Dual Standby"
+ * model was chosen, where it's impossible, so keep only pointer to
+ * current modem, if model will be changed to "Dual SIM Dual Active",
+ * change get_current_imsi() and
+ * add into it iteration, also patch
+ * "[PATCH 2/8] network: add modem section into config" which was
+ * abondoned in current patch set, could be usefull as well (but not
+ * confg value in it, due everything could change). */
+ /* char *ifname; */
+ /* bool active; */
+ char *imsi_hash;
+ resourced_hw_net_protocol_type protocol;
+};
+
+static struct modem_state *current_modem;
+static GSList *modems; /* list of available modems with roaming state */
+
+#ifdef DEBUG_ENABLED
+#define _D_DBUS _D
+#else
+#define _D_DBUS(s, args...) ({ do { } while (0); })
+#endif /*DEBUG_ENABLED*/
+
+static bool check_current_modem(const char *modem_name, int sim_number)
+{
+ int digit_pos = 0;
+ ret_value_msg_if(!modem_name, false, "Invalid argument!");
+
+ ret_value_msg_if(sim_number >= 10, false, "Unsupported sim number %d", sim_number);
+ digit_pos = strlen(modem_name);
+ ret_value_msg_if(!digit_pos, false, "Invalid argument!");
+ return modem_name[digit_pos - 1] == '0' + sim_number;
+}
+
+static void default_data_service_change_cb(keynode_t *key, void *data)
+{
+ int current_sim = vconf_keynode_get_int(key);
+ GSList *iter;
+
+ _D("default data service has changed: key = %s, value = %d(int)\n",
+ vconf_keynode_get_name(key), current_sim);
+
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ if (!modem->name)
+ continue;
+ if (check_current_modem(modem->name, current_sim)) {
+ current_modem = modem;
+ break;
+ }
+ }
+}
+
+static int get_current_sim(void)
+{
+ int sim_slot_count = 0;
+ int current_sim = 0;
+ ret_value_msg_if(vconf_get_int(
+ VCONFKEY_TELEPHONY_SIM_SLOT_COUNT, &sim_slot_count) != 0, -1,
+ "failed to get sim slot count");
+
+ if(sim_slot_count == SIM_SLOT_SINGLE) {
+ _D("It's single sim model");
+ return -1;
+ }
+
+ ret_value_msg_if(vconf_get_int(
+ VCONF_TELEPHONY_DEFAULT_DATA_SERVICE, &current_sim) != 0, -1,
+ "failed to get default data service = %d\n", current_sim);
+ return current_sim;
+}
+
+static void init_available_modems(void)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter, iter_array;
+ int i = 0;
+ int current_sim;
+
+ do {
+ msg = dbus_method_sync(DBUS_TELEPHONY_SERVICE,
+ DBUS_TELEPHONY_DEFAULT_PATH,
+ DBUS_TELEPHONY_SERVICE_MANAGER,
+ DBUS_TELEPHONY_GET_MODEMS,
+ NULL, NULL);
+ if (msg)
+ break;
+ _E("Re-try to sync DBUS message, err_count : %d", i);
+ } while (i++ < RETRY_MAX);
+
+ if (!msg) {
+ _E("Failed to sync DBUS message.");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ dbus_message_iter_init (msg, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ current_sim = get_current_sim();
+
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID) {
+ const char *name;
+ struct modem_state *state = (struct modem_state *)malloc(
+ sizeof(struct modem_state));
+ memset(state, 0, sizeof(struct modem_state));
+ dbus_message_iter_get_basic (&iter_array, &name);
+ _D("modem name %s", name);
+ dbus_message_iter_next (&iter_array);
+ state->name = strdup(name);
+ state->roaming = false;
+ modems = g_slist_prepend(modems, state);
+ if (check_current_modem(state->name, current_sim))
+ current_modem = state;
+ }
+
+ vconf_notify_key_changed(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE,
+ default_data_service_change_cb, NULL);
+
+ dbus_message_unref(msg);
+ dbus_error_free(&err);
+}
+
+static void hash_imsi(struct modem_state *modem)
+{
+ int i;
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ unsigned char md[SHA256_DIGEST_LENGTH];
+ SHA256_Update(&ctx, modem->imsi, strlen(modem->imsi));
+ SHA256_Final(md, &ctx);
+ if (!modem->imsi_hash) {
+ modem->imsi_hash = (char *)malloc(SHA256_DIGEST_LENGTH * 2 + 1);
+ ret_msg_if(!modem->imsi_hash, "Can't allocate buffer for imsi_hash!");
+ }
+ _SD("make hash for imsi %s", modem->imsi);
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+ sprintf(modem->imsi_hash + (i * 2), "%02x", md[i]);
+}
+
+static void fill_modem_imsi(struct modem_state *modem)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ char tel_path[MAX_PATH_LENGTH];
+ char *plmn = NULL;
+ int plmn_len;
+ char *msin = NULL;
+ int msin_len;
+ int i = 0;
+
+ snprintf(tel_path, sizeof(tel_path), "%s/%s", DBUS_TELEPHONY_DEFAULT_PATH, modem->name);
+ do {
+ msg = dbus_method_sync(DBUS_TELEPHONY_SERVICE,
+ tel_path,
+ DBUS_TELEPHONY_SIM_INTERFACE,
+ DBUS_TELEPHONY_GET_IMSI,
+ NULL, NULL);
+ if (msg)
+ break;
+ _E("Re-try to sync DBUS message, err_count : %d", i);
+ } while (i++ < RETRY_MAX);
+
+ if (!msg) {
+ _E("Failed to sync DBUS message.");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ dbus_message_iter_init (msg, &iter);
+ _D_DBUS("dbus message type %d", dbus_message_iter_get_arg_type(&iter));
+ ret_msg_if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING,
+ "Return for %s isn't variant type as expected",
+ DBUS_FREEDESKTOP_PROPERTIES);
+ dbus_message_iter_get_basic (&iter, &plmn);
+ _D_DBUS("plmn value %d", plmn);
+ plmn_len = strlen(plmn);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic (&iter, &msin);
+ _D_DBUS("msin value %d", msin);
+ msin_len = strlen(msin);
+ if (!modem->imsi) { /* it's reinit case */
+ modem->imsi = malloc(plmn_len + msin_len + 1);
+ ret_msg_if(!modem->imsi, "Can't allocate string for imsi");
+ }
+ if (msin_len + plmn_len >= IMSI_LENGTH) {
+ _D("Incorrect length of mobile subscriber identifier + net id");
+ return;
+ }
+ snprintf(modem->imsi, IMSI_LENGTH, "%s%s", plmn, msin);
+ hash_imsi(modem);
+}
+
+static void init_modem_imsi(void)
+{
+ GSList *iter;
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ fill_modem_imsi(modem);
+ }
+}
+
+static void fill_modem_state(struct modem_state *modem)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter, var;
+ char tel_path[MAX_PATH_LENGTH];
+ int i = 0;
+ char *params[2] = {DBUS_TELEPHONY_SERVICE_NETWORK, DBUS_TELEPHONY_ROAMING_STATUS};
+
+
+ snprintf(tel_path, sizeof(tel_path), "%s/%s", DBUS_TELEPHONY_DEFAULT_PATH, modem->name);
+ do {
+ msg = dbus_method_sync(DBUS_TELEPHONY_SERVICE,
+ tel_path,
+ DBUS_FREEDESKTOP_PROPERTIES,
+ DBUS_TELEPHONY_GET,
+ "ss", params);
+ if (msg)
+ break;
+ _E("Re-try to sync DBUS message, err_count : %d", i);
+ } while (i++ < RETRY_MAX);
+
+ if (!msg) {
+ _E("Failed to sync DBUS message.");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ dbus_message_iter_init (msg, &iter);
+ _D_DBUS("dbus message type %d", dbus_message_iter_get_arg_type(&iter));
+ ret_msg_if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT,
+ "Return for %s isn't variant type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+ dbus_message_iter_recurse(&iter, &var);
+ _D_DBUS("dbus message variant type %d", dbus_message_iter_get_arg_type(&var));
+ ret_msg_if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN,
+ "Return for %s isn't boolean type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+
+ dbus_message_iter_get_basic (&var, &modem->roaming);
+ _D("modem roaming value %d", modem->roaming);
+}
+
+static void fill_protocol(struct modem_state *modem)
+{
+ DBusError err;
+ DBusMessage *msg;
+ DBusMessageIter iter, var;
+ char tel_path[MAX_PATH_LENGTH];
+ int i = 0;
+ char *params[2] = {DBUS_TELEPHONY_SERVICE_NETWORK, DBUS_TELEPHONY_SERVICE_TYPE};
+
+
+ snprintf(tel_path, sizeof(tel_path), "%s/%s", DBUS_TELEPHONY_DEFAULT_PATH, modem->name);
+ do {
+ msg = dbus_method_sync(DBUS_TELEPHONY_SERVICE,
+ tel_path,
+ DBUS_FREEDESKTOP_PROPERTIES,
+ DBUS_TELEPHONY_GET,
+ "ss", params);
+ if (msg)
+ break;
+ _E("Re-try to sync DBUS message, err_count : %d", i);
+ } while (i++ < RETRY_MAX);
+
+ if (!msg) {
+ _E("Failed to sync DBUS message.");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ dbus_message_iter_init (msg, &iter);
+ _D_DBUS("dbus message type %d", dbus_message_iter_get_arg_type(&iter));
+ ret_msg_if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT,
+ "Return for %s isn't variant type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+ dbus_message_iter_recurse(&iter, &var);
+ _D_DBUS("dbus message variant type %d", dbus_message_iter_get_arg_type(&var));
+ ret_msg_if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_INT32,
+ "Return for %s isn't int type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+
+ dbus_message_iter_get_basic (&var, &modem->protocol);
+ _D("modem roaming value %d", modem->protocol);
+}
+
+/**
+ * @brief Get initial value for roaming and sets callback for handling roaming change
+ */
+static void init_roaming_states(void)
+{
+ GSList *iter;
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ fill_modem_state(modem);
+ }
+}
+
+static void init_protocols(void)
+{
+ GSList *iter;
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ fill_protocol(modem);
+ }
+}
+
+
+/**
+ * Response format:
+ * signal sender=:1.273 -> dest=(null destination) serial=546
+ * path=/org/tizen/telephony/sprdmodem0;
+ * interface=org.freedesktop.DBus.Properties;
+ * member=PropertiesChanged
+ * string "org.tizen.telephony.Network"
+ * array [
+ * ...
+ * dict entry(
+ * string "roaming_status"
+ * variant boolean false
+ * )
+ * ...
+ * dict entry(
+ * string "service_type"
+ * variant int32 3
+ * )
+ * ]
+ * array [
+ * ]
+ **/
+static void edbus_telephony_changed(void *data, DBusMessage *msg)
+{
+ struct modem_state *modem = (struct modem_state *)data;
+ char *property;
+ /* parse msg */
+ DBusMessageIter iter, dict, prop, bool_iter;
+
+ _D_DBUS("it's signal by %s path", dbus_message_get_path(msg));
+ dbus_message_iter_init (msg, &iter);
+ dbus_message_iter_next(&iter);
+ /* call dbus_message_iter_next(&iter) */
+ _D_DBUS("dbus message type %d", dbus_message_iter_get_arg_type(&iter));
+
+ while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
+ dbus_message_iter_recurse(&iter, &dict);
+ _D_DBUS("dbus message variant type %d", dbus_message_iter_get_arg_type(&dict));
+ ret_msg_if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY,
+ "Return for %s isn't variant type as expected",
+ modem->path);
+
+ dbus_message_iter_recurse(&dict, &prop);
+ _D_DBUS("dbus message roaming type %d", dbus_message_iter_get_arg_type(&prop));
+ ret_msg_if (dbus_message_iter_get_arg_type(&prop) != DBUS_TYPE_STRING,
+ "Return for %s isn't boolean type as expected",
+ modem->path);
+
+ dbus_message_iter_get_basic (&prop, &property);
+
+ if (strcmp(property, DBUS_TELEPHONY_ROAMING_STATUS) == 0) {
+ dbus_message_iter_next(&prop); /* it's variant here, expand it */
+ dbus_message_iter_recurse(&prop, &bool_iter);
+ ret_msg_if (dbus_message_iter_get_arg_type(&bool_iter) != DBUS_TYPE_BOOLEAN,
+ "Return for %s isn't variant type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+
+ dbus_message_iter_get_basic (&bool_iter, &modem->roaming);
+ _D("Roaming state for modem %s has changed", modem->name);
+ _D("roaming state now is %d", modem->roaming);
+ } else if (strcmp(property, DBUS_TELEPHONY_SERVICE_TYPE) == 0) {
+ dbus_message_iter_next(&prop); /* it's variant here, expand it */
+ dbus_message_iter_recurse(&prop, &bool_iter);
+ ret_msg_if (dbus_message_iter_get_arg_type(&bool_iter) != DBUS_TYPE_INT32,
+ "Return for %s isn't variant type as expected", DBUS_FREEDESKTOP_PROPERTIES);
+
+ dbus_message_iter_get_basic (&bool_iter, &modem->protocol);
+ _D("Protocol for modem %s has changed", modem->name);
+ _D("protocol now is %d", modem->protocol);
+ } else {
+ _D("Unnecessary property %s", property);
+ return;
+ }
+ dbus_message_iter_next(&iter);
+ }
+}
+
+static void regist_telephony_callbacks(void)
+{
+ resourced_ret_c ret;
+ GSList *iter;
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ modem->path = (char *)malloc(sizeof(DBUS_TELEPHONY_DEFAULT_PATH) + strlen(modem->name) + 2);
+ sprintf(modem->path, "%s/%s", DBUS_TELEPHONY_DEFAULT_PATH, modem->name);
+ ret = register_edbus_signal_handler(modem->path,
+ DBUS_FREEDESKTOP_PROPERTIES,
+ DBUS_TELEPHONY_PROPERTIES_CHANGED,
+ edbus_telephony_changed, modem);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Could not register edbus path %s", modem->path);
+ modem->path = NULL;
+ continue;
+ }
+ }
+}
+
+static void edbus_sim_status_changed(void *data, DBusMessage *msg)
+{
+ struct modem_state *modem = (struct modem_state *)data;
+ int sim_status = 0;
+ int arg_type = 0;
+ /* parse msg */
+ DBusMessageIter iter;
+
+ _D("it's signal by %s path", dbus_message_get_path(msg));
+ dbus_message_iter_init (msg, &iter);
+ arg_type = dbus_message_iter_get_arg_type(&iter);
+ dbus_message_iter_get_basic(&iter, &sim_status);
+
+ _D("sim status type %d, %d", sim_status, arg_type);
+ if (sim_status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
+ /* we could request IMSI */
+ fill_modem_imsi(modem);
+ }
+}
+
+
+static void regist_sim_status_callbacks(void)
+{
+ resourced_ret_c ret;
+ GSList *iter;
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ modem->path = (char *)malloc(sizeof(DBUS_TELEPHONY_DEFAULT_PATH) + strlen(modem->name) + 2);
+ sprintf(modem->path, "%s/%s", DBUS_TELEPHONY_DEFAULT_PATH, modem->name);
+ ret = register_edbus_signal_handler(modem->path,
+ DBUS_TELEPHONY_SIM_INTERFACE,
+ DBUS_TELEPHONY_STATUS,
+ edbus_sim_status_changed, modem);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("Could not register edbus path %s", modem->path);
+ modem->path = NULL;
+ continue;
+ }
+ }
+}
+
+static void init_telephony(void)
+{
+ execute_once {
+ init_available_modems();
+ init_roaming_states();
+ init_modem_imsi();
+ init_protocols();
+ regist_telephony_callbacks();
+ regist_sim_status_callbacks();
+ }
+}
+
+resourced_roaming_type get_current_roaming(void)
+{
+ init_telephony(); /* one time lazy initialization */
+ ret_value_msg_if(!current_modem, RESOURCED_ROAMING_UNKNOWN,
+ "There is no current modem!");
+
+ return current_modem->roaming ? RESOURCED_ROAMING_ENABLE:
+ RESOURCED_ROAMING_DISABLE;
+}
+
+char *get_imsi_hash(char *imsi)
+{
+ GSList *iter;
+
+ if (!imsi) {
+ _E("imsi is NULL");
+ return NULL;
+ }
+
+ gslist_for_each_item(iter, modems) {
+ struct modem_state *modem = (struct modem_state *)iter->data;
+ if (modem->imsi == NULL)
+ continue;
+ if(!strcmp(imsi, modem->imsi))
+ return modem->imsi_hash;
+ }
+ return NULL;
+}
+
+char *get_current_modem_imsi(void)
+{
+ init_telephony(); /* one time lazy initialization */
+ ret_value_msg_if(current_modem == NULL, NULL, "Current modem isn't " \
+ "selected");
+
+ return current_modem->imsi;
+}
+
+bool check_event_in_current_modem(const char *imsi_hash,
+ const resourced_iface_type iftype)
+{
+ char *current_imsi_hash;
+ if (iftype != RESOURCED_IFACE_DATACALL)
+ return false;
+
+ current_imsi_hash = get_imsi_hash(get_current_modem_imsi());
+ /* if we don't have current_imsi_hash
+ * do everything as before */
+ return (current_imsi_hash && imsi_hash) ?
+ strcmp(imsi_hash, current_imsi_hash) : false;
+}
+
+static void modem_free(gpointer data)
+{
+ struct modem_state *modem = (struct modem_state *)data;
+ if (modem->imsi)
+ free(modem->imsi);
+ if (modem->name)
+ free(modem->name);
+ if (modem->path)
+ free(modem->path);
+}
+
+resourced_hw_net_protocol_type get_current_protocol(resourced_iface_type iftype)
+{
+ if (iftype != RESOURCED_IFACE_DATACALL)
+ return RESOURCED_PROTOCOL_NONE;
+
+ init_telephony();
+ ret_value_msg_if(current_modem == NULL, RESOURCED_PROTOCOL_NONE,
+ "Current modem isn't selected");
+
+ return current_modem->protocol;
+}
+
+void finilize_telephony(void)
+{
+ g_slist_free_full(modems, modem_free);
+ vconf_ignore_key_changed(VCONF_TELEPHONY_DEFAULT_DATA_SERVICE,
+ default_data_service_change_cb);
+
+}
+
diff --git a/src/network/tethering-restriction.c b/src/network/tethering-restriction.c
index ff845022..60abdfe4 100644
--- a/src/network/tethering-restriction.c
+++ b/src/network/tethering-restriction.c
@@ -34,24 +34,17 @@
resourced_ret_c apply_tethering_restriction(
const enum traffic_restriction_type type)
{
-#ifdef TETHERING_FEATURE
- static int tethering_exclude;
+ _D("apply tethering rule %d", type);
switch (type) {
case RST_SET:
- if (!tethering_exclude)
- return fwrite_str(PATH_TO_PROC_IP_FORWARD, "0");
- return RESOURCED_ERROR_NONE;
+ return fwrite_str(PATH_TO_PROC_IP_FORWARD, "0");
case RST_UNSET:
- tethering_exclude = 0;
return fwrite_str(PATH_TO_PROC_IP_FORWARD, "1");
case RST_EXCLUDE:
- tethering_exclude = 1;
return fwrite_str(PATH_TO_PROC_IP_FORWARD, "1");
default:
return RESOURCED_ERROR_INVALID_PARAMETER;
}
-#else
return RESOURCED_ERROR_NONE;
-#endif /* TETHERING_FEATURE */
}
diff --git a/src/network/update.c b/src/network/update.c
index e141952a..6e256d6d 100755
--- a/src/network/update.c
+++ b/src/network/update.c
@@ -30,7 +30,6 @@
#include "const.h"
#include "edbus-handler.h"
#include "macro.h"
-#include "rd-network.h"
#include "trace.h"
static E_DBus_Signal_Handler *handler;
diff --git a/src/proc-stat/CMakeLists.txt b/src/proc-stat/CMakeLists.txt
index 573c7548..cdbf5f42 100644
--- a/src/proc-stat/CMakeLists.txt
+++ b/src/proc-stat/CMakeLists.txt
@@ -3,9 +3,10 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX})
INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
${PROC-STAT_SOURCE_DIR}/include)
+SET (REQUIRES_LIST dlog glib-2.0)
+
INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs_proc_stat REQUIRED dlog
- glib-2.0)
+pkg_check_modules(pkgs_proc_stat REQUIRED ${REQUIRES_LIST})
FOREACH(flag ${pkgs_proc_stat_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
@@ -26,7 +27,7 @@ SET(SOURCES
ADD_LIBRARY(${PROC-STAT} SHARED ${SOURCES})
-TARGET_LINK_LIBRARIES(${PROC-STAT} ${${PROC-STAT}_LDFLAGS})
+TARGET_LINK_LIBRARIES(${PROC-STAT} ${pkgs_proc_stat_LDFLAGS})
SET_TARGET_PROPERTIES(${PROC-STAT}
PROPERTIES
diff --git a/src/proc-stat/include/proc-main.h b/src/proc-stat/include/proc-main.h
index d4afec27..8bf9eb2b 100644
--- a/src/proc-stat/include/proc-main.h
+++ b/src/proc-stat/include/proc-main.h
@@ -31,17 +31,18 @@
#include "daemon-options.h"
#include "resourced.h"
#include "const.h"
+#include "memcontrol.h"
#define PROC_BUF_MAX 64
-#define PROC_NAME_MAX 512
+#define PROC_NAME_MAX 1024
typedef GSList *pid_info_list;
enum application_type {
- RESOURCED_APP_TYPE_UNKNOWN,
- RESOURCED_APP_TYPE_GUI,
- RESOURCED_APP_TYPE_SERVICE,
- RESOURCED_APP_TYPE_GROUP,
+ PROC_TYPE_UNKNOWN,
+ PROC_TYPE_GUI,
+ PROC_TYPE_SERVICE,
+ PROC_TYPE_GROUP,
};
struct pid_info_t {
@@ -52,18 +53,19 @@ struct pid_info_t {
struct proc_process_info_t {
char appid[MAX_PATH_LENGTH];
char pkgname[MAX_PATH_LENGTH];
+ pid_t main_pid;
pid_info_list pids;
int proc_exclude;
int runtime_exclude;
int memcg_idx;
- int state;
+ struct memcg_info_t *memcg_info;
int type;
};
struct proc_status {
pid_t pid;
char* appid;
- struct proc_process_info_t *processinfo;
+ struct proc_process_info_t *ppi;
};
enum proc_exclude_type {
@@ -77,14 +79,17 @@ enum {
};
enum proc_prelaunch_flags {
- PROC_LARGE_HEAP = 0x01u, /* for mark large heap */
+ PROC_NONE = 0x00u,
+ PROC_LARGEMEMORY = 0x01u, /* for mark large memory */
PROC_SIGTERM = 0x02u, /* for make killer kill victim by SIGTERM */
+ PROC_WEBAPP = 0x04u, /* for checking webapp */
};
extern int current_lcd_state;
+extern GSList *proc_process_list;
-void proc_add_pid_list(struct proc_process_info_t *process_info, int pid, enum application_type type);
+void proc_add_pid_list(struct proc_process_info_t *ppi, int pid, enum application_type type);
int resourced_proc_init(const struct daemon_opts *opts);
@@ -97,15 +102,19 @@ int resourced_proc_excluded(const char *app_name);
int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_name);
+void resourced_proc_dump(int type, const char *path);
+
struct proc_process_info_t *find_process_info(const char *appid, const pid_t pid, const char *pkgid);
struct pid_info_t *new_pid_info(const pid_t pid, const int type);
-void proc_set_process_info_memcg(struct proc_process_info_t *process_info, int memcg_idx);
+void proc_set_process_info_memcg(struct proc_process_info_t *ppi,
+ int memcg_idx, struct memcg_info_t *memcg_info);
resourced_ret_c proc_set_runtime_exclude_list(const int pid, int type);
struct proc_process_info_t *proc_add_process_list(const int type, const pid_t pid, const char *appid, const char *pkgid);
+struct proc_process_info_t * proc_create_process_list(const char *appid, const char *pkgid);
int proc_remove_process_list(const pid_t pid);
void proc_set_apptype(const char *appid, const char *pkgid, int type);
-
+int proc_get_apptype(const pid_t pid);
#endif /*__PROC_MAIN_H__ */
diff --git a/src/proc-stat/include/proc-process.h b/src/proc-stat/include/proc-process.h
index f118599d..c0d11a38 100644
--- a/src/proc-stat/include/proc-process.h
+++ b/src/proc-stat/include/proc-process.h
@@ -65,4 +65,7 @@ pid_t find_pid_from_cmdline(char *cmdline);
void proc_set_group(pid_t onwerpid, pid_t childpid);
+int proc_set_service_oomscore(const pid_t pid, const int oom_score);
+
+
#endif /*__PROC_PROCESS_H__*/
diff --git a/src/proc-stat/include/proc-usage-stats-helper.h b/src/proc-stat/include/proc-usage-stats-helper.h
new file mode 100644
index 00000000..898ee448
--- /dev/null
+++ b/src/proc-stat/include/proc-usage-stats-helper.h
@@ -0,0 +1,85 @@
+/*
+ * 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 proc-usage-stats-helper.h
+ * @desc process usage stats helper methods
+ **/
+
+#ifndef __RESOURCED_PROC_USAGE_STATS_HELPER_H__
+#define __RESOURCED_PROC_USAGE_STATS_HELPER_H__
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <resourced.h>
+#include <E_DBus.h>
+#include <pthread.h>
+#include <time.h>
+
+#define INVALID_PROCESS_INFO_FIELD_VALUE -1
+
+#define TASK_NAME_SIZE 256
+
+/* Process memory usage info struct (original design in runtime-info API) */
+struct process_memory_info_s {
+ int vsz; /**< Virtual memory size (KiB) */
+ int rss; /**< Resident set size (KiB) */
+ int pss; /**< Proportional set size (KiB) */
+ int shared_clean; /**< Not modified and mapped by other processes (KiB) */
+ int shared_dirty; /**< Modified and mapped by other processes (KiB) */
+ int private_clean; /**< Not modified and available only to that process (KiB) */
+ int private_dirty; /**< Modified and available only to that process (KiB) */
+};
+
+struct process_cpu_usage_s {
+ int utime; /**< Amount of time that this process has spent in user mode */
+ int stime; /**< Amount of time that this process has spent in kernel mode */
+};
+
+
+typedef enum {
+ RUNTIME_INFO_TASK_MEMORY, /**< Represents memory usage requests */
+ RUNTIME_INFO_TASK_CPU /**< Represents cpu usage requests */
+} runtime_info_task_type;
+
+/* Runtime info task struct. Represents each request received by the runtime-info library */
+struct runtime_info_task {
+ runtime_info_task_type task_type; /**< Task type */
+ int task_size; /**< Size of the process id array */
+ int pipe_fds[2]; /**< fds of the read and write end of the pipe */
+ char task_name[TASK_NAME_SIZE]; /**< The name assigned to task */
+ int *pid_list; /**< Pointer to the process id array in the dbus message */
+ void *usage_info_list; /**< Pointer to the memory containing the usage info results */
+ DBusMessage *task_msg; /**< Pointer to the dbus message sent by runtime-info. */
+};
+
+void proc_get_memory_usage(int pid, struct process_memory_info_s *mem_info);
+void proc_get_cpu_usage(int pid, struct process_cpu_usage_s *cpu_usage);
+int proc_read_from_usage_struct(void *usage_info_list, int index, int *result, runtime_info_task_type task_type);
+void proc_get_task_name(char *task_name, int size, runtime_info_task_type task_type);
+void proc_free_runtime_info_task(struct runtime_info_task *rt_task);
+
+/* TODO
+ * ** Return different failure values in reply dbus message according to reason
+ * ** Add some kind of identifier for the process making the method call,
+ * and use this id in the task file name
+ * ** Change to thread pool if needed
+ */
+#endif /* __RESOURCED_PROC_USAGE_STATS_HELPER_H__ */
+
diff --git a/src/proc-stat/include/proc-usage-stats.h b/src/proc-stat/include/proc-usage-stats.h
new file mode 100644
index 00000000..c1fcb0a2
--- /dev/null
+++ b/src/proc-stat/include/proc-usage-stats.h
@@ -0,0 +1,33 @@
+/*
+ * 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 proc-usage-stats.h
+ * @desc process usage stats module init
+ **/
+
+#ifndef __RESOURCED_PROC_USAGE_STATS_H__
+#define __RESOURCED_PROC_USAGE_STATS_H__
+#include <resourced.h>
+
+/* Initialize proc usage stats module by registering it in edbus. */
+resourced_ret_c proc_usage_stats_init(void);
+
+#endif /* __RESOURCED_PROC_USAGE_STATS_H__ */
+
diff --git a/src/proc-stat/proc-main.c b/src/proc-stat/proc-main.c
index 2b96fbdf..81e43658 100644
--- a/src/proc-stat/proc-main.c
+++ b/src/proc-stat/proc-main.c
@@ -36,6 +36,7 @@
#include "trace.h"
#include "proc-handler.h"
#include "proc-monitor.h"
+#include "proc-usage-stats.h"
#include "module.h"
#include "macro.h"
#include "appid-helper.h"
@@ -47,6 +48,7 @@ static Ecore_File_Monitor *exclude_list_monitor;
static const unsigned int exclude_list_limit = 1024;
static int proc_notifd;
#define BASE_UGPATH_PREFIX "/usr/ug/bin"
+#define LOG_PREFIX "resourced.log"
enum proc_state {
PROC_STATE_DEFAULT,
@@ -54,6 +56,26 @@ enum proc_state {
PROC_STATE_BACKGROUND,
};
+static char *convert_to_proctype_str(int type)
+{
+ char *tmp = NULL;
+ switch (type) {
+ case PROC_TYPE_GUI:
+ tmp = "GUI";
+ break;
+ case PROC_TYPE_SERVICE:
+ tmp = "SERVICE";
+ break;
+ case PROC_TYPE_GROUP:
+ tmp = "GROUP";
+ break;
+ default:
+ tmp = "NONE";
+ break;
+ }
+ return tmp;
+}
+
/*
* @brief pid_info_list is only for pid_info_t
*/
@@ -86,7 +108,7 @@ static struct pid_info_t *find_pid_info(pid_info_list pids, const pid_t pid)
struct pid_info_t pid_to_find = {
.pid = pid,
/* now it doesn't matter */
- .type = RESOURCED_APP_TYPE_UNKNOWN,
+ .type = PROC_TYPE_UNKNOWN,
};
GSList *found = NULL;
@@ -100,24 +122,24 @@ static struct pid_info_t *find_pid_info(pid_info_list pids, const pid_t pid)
return NULL;
}
-void proc_add_pid_list(struct proc_process_info_t *process_info, int pid, enum application_type type)
+void proc_add_pid_list(struct proc_process_info_t *ppi, int pid, enum application_type type)
{
struct pid_info_t pid_to_find = {
.pid = pid,
/* now it doesn't matter */
- .type = RESOURCED_APP_TYPE_UNKNOWN,
+ .type = PROC_TYPE_UNKNOWN,
};
GSList *found = NULL;
- if (process_info->pids)
- found = g_slist_find_custom((GSList *)process_info->pids,
+ if (ppi->pids)
+ found = g_slist_find_custom((GSList *)ppi->pids,
&pid_to_find, compare_pid);
if (found)
return;
pthread_mutex_lock(&proc_mutex);
- process_info->pids = g_slist_prepend(process_info->pids, new_pid_info(pid, type));
+ ppi->pids = g_slist_prepend(ppi->pids, new_pid_info(pid, type));
pthread_mutex_unlock(&proc_mutex);
}
@@ -149,48 +171,13 @@ static resourced_ret_c proc_check_ug(pid_t pid)
return RESOURCED_ERROR_NONE;
}
-static void proc_set_service_oomscore(const pid_t pid, const int state)
-{
- int oom_score = OOMADJ_SERVICE_DEFAULT;
- switch(state) {
- case PROC_STATE_DEFAULT:
- oom_score = OOMADJ_SERVICE_DEFAULT;
- break;
- case PROC_STATE_FOREGROUND:
- oom_score = OOMADJ_SERVICE_FOREGRD;
- break;
- case PROC_STATE_BACKGROUND:
- oom_score = OOMADJ_SERVICE_BACKGRD;
- break;
- }
- proc_set_oom_score_adj(pid, oom_score);
-}
-
-static pid_t get_service_pid(struct proc_process_info_t *info_t)
-{
- GSList *iter = NULL;
-
- if (!info_t) {
- _D("Can't find process_info");
- return RESOURCED_ERROR_FAIL;
- }
-
- gslist_for_each_item(iter, info_t->pids) {
- struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
-
- if (pid_info->type == RESOURCED_APP_TYPE_SERVICE) {
- _D("get_service_pid : pid (%d), type (%d)", pid_info->pid, pid_info->type);
- return pid_info->pid;
- }
- }
- return RESOURCED_ERROR_NO_DATA;
-}
-
-void proc_set_process_info_memcg(struct proc_process_info_t *process_info, int memcg_idx)
+void proc_set_process_info_memcg(struct proc_process_info_t *ppi,
+ int memcg_idx, struct memcg_info_t *memcg_info)
{
- if (!process_info)
+ if (!ppi)
return;
- process_info->memcg_idx = memcg_idx;
+ ppi->memcg_idx = memcg_idx;
+ ppi->memcg_info = memcg_info;
}
struct proc_process_info_t *find_process_info(const char *appid, const pid_t pid, const char *pkgid)
@@ -224,47 +211,31 @@ struct proc_process_info_t *find_process_info(const char *appid, const pid_t pid
return NULL;
}
-static resourced_ret_c proc_update_process_state(const pid_t pid, const int state)
-{
- struct proc_process_info_t *process_info = NULL;
- pid_t service_pid;
- process_info = find_process_info(NULL, pid, NULL);
- if (!process_info) {
- _E("Current pid (%d) didn't have any process list", pid);
- return RESOURCED_ERROR_INVALID_PARAMETER;
- }
- process_info->state = state;
- service_pid = get_service_pid(process_info);
- if (service_pid)
- proc_set_service_oomscore(service_pid, state);
- return RESOURCED_ERROR_NONE;
-}
-
resourced_ret_c proc_set_runtime_exclude_list(const int pid, int type)
{
GSList *iter = NULL;
- struct proc_process_info_t *process_info = NULL;
- struct pid_info_t *found_pid = NULL;
+ struct proc_process_info_t *ppi = NULL;
+ struct pid_info_t *found = NULL;
gslist_for_each_item(iter, proc_process_list) {
- process_info = (struct proc_process_info_t *)iter->data;
- if (!process_info->pids)
+ ppi = (struct proc_process_info_t *)iter->data;
+ if (!ppi->pids)
continue;
- found_pid = find_pid_info(process_info->pids, pid);
- if(!found_pid)
+ found = find_pid_info(ppi->pids, pid);
+ if(!found)
continue;
- if(process_info->runtime_exclude) {
+ if(ppi->runtime_exclude) {
if (type == PROC_EXCLUDE)
- process_info->runtime_exclude++;
+ ppi->runtime_exclude++;
else
- process_info->runtime_exclude--;
+ ppi->runtime_exclude--;
} else
- process_info->runtime_exclude = type;
+ ppi->runtime_exclude = type;
_D("found_pid %d, set proc exclude list, type = %d, exclude = %d",
- found_pid->pid, type, process_info->runtime_exclude);
+ found->pid, type, ppi->runtime_exclude);
break;
}
return RESOURCED_ERROR_NONE;
@@ -272,111 +243,183 @@ resourced_ret_c proc_set_runtime_exclude_list(const int pid, int type)
struct proc_process_info_t * proc_add_process_list(const int type, const pid_t pid, const char *appid, const char *pkgid)
{
- struct proc_process_info_t *process_info;
+ struct proc_process_info_t *ppi;
+ int owner_oom = 0;
if (!appid)
return NULL;
- process_info = find_process_info(appid, pid, pkgid);
+ ppi = find_process_info(appid, pid, pkgid);
/* do not add if it already in list */
- if (process_info && find_pid_info(process_info->pids, pid))
- return process_info;
+ if (ppi && find_pid_info(ppi->pids, pid))
+ return ppi;
- if (!process_info) {
- process_info = malloc(sizeof(struct proc_process_info_t));
- if (!process_info)
+ if (!ppi) {
+ ppi = malloc(sizeof(struct proc_process_info_t));
+ if (!ppi)
return NULL;
- memset(process_info, 0, sizeof(struct proc_process_info_t));
- strncpy(process_info->appid, appid, MAX_NAME_LENGTH - 1);
- process_info->proc_exclude = resourced_proc_excluded(appid);
+ memset(ppi, 0, sizeof(struct proc_process_info_t));
+ strncpy(ppi->appid, appid, MAX_NAME_LENGTH - 1);
+ ppi->proc_exclude = resourced_proc_excluded(appid);
if (pkgid)
- strncpy(process_info->pkgname, pkgid, MAX_NAME_LENGTH - 1);
+ strncpy(ppi->pkgname, pkgid, MAX_NAME_LENGTH - 1);
else
- extract_pkgname(process_info->appid, process_info->pkgname,
+ extract_pkgname(ppi->appid, ppi->pkgname,
MAX_NAME_LENGTH);
pthread_mutex_lock(&proc_mutex);
proc_process_list = g_slist_prepend(proc_process_list,
- process_info);
+ ppi);
pthread_mutex_unlock(&proc_mutex);
- process_info->state = PROC_STATE_DEFAULT;
- }
- if (proc_check_ug(pid) == RESOURCED_ERROR_NONFREEZABLE)
- process_info->runtime_exclude = PROC_EXCLUDE;
- if (type == RESOURCED_APP_TYPE_SERVICE)
- proc_set_service_oomscore(pid, process_info->state);
+ } else if (type == PROC_TYPE_SERVICE && ppi->main_pid > 0)
+ proc_get_oom_score_adj(ppi->main_pid, &owner_oom);
- proc_add_pid_list(process_info, pid, type);
- return process_info;
+ if (proc_check_ug(pid) == RESOURCED_ERROR_NONFREEZABLE)
+ ppi->runtime_exclude = PROC_EXCLUDE;
+ if (type == PROC_TYPE_SERVICE)
+ proc_set_service_oomscore(pid, owner_oom);
+
+ if (type == PROC_TYPE_GUI) {
+ if (ppi->main_pid && pid != ppi->main_pid){
+ if (proc_get_oom_score_adj(pid, &owner_oom) < 0) {
+ struct pid_info_t *found = NULL;
+ found = find_pid_info(ppi->pids, ppi->main_pid);
+ if(found) {
+ ppi->pids = g_slist_remove(ppi->pids,
+ found);
+ free(found);
+ }
+ ppi->main_pid = pid;
+ }
+ } else
+ ppi->main_pid = pid;
+ }
+ proc_add_pid_list(ppi, pid, type);
+ return ppi;
}
struct proc_process_info_t * proc_create_process_list(const char *appid, const char *pkgid)
{
- struct proc_process_info_t *process_info;
+ struct proc_process_info_t *ppi;
if (!appid)
return NULL;
- process_info = find_process_info(appid, 0, pkgid);
+ ppi = find_process_info(appid, 0, pkgid);
/* do not add if it already in list */
- if (process_info)
- return process_info;
+ if (ppi)
+ return ppi;
- if (!process_info) {
- process_info = malloc(sizeof(struct proc_process_info_t));
- if (!process_info)
+ if (!ppi) {
+ ppi = malloc(sizeof(struct proc_process_info_t));
+ if (!ppi)
return NULL;
- memset(process_info, 0, sizeof(struct proc_process_info_t));
- strncpy(process_info->appid, appid, MAX_NAME_LENGTH - 1);
- process_info->proc_exclude = resourced_proc_excluded(appid);
+ memset(ppi, 0, sizeof(struct proc_process_info_t));
+ strncpy(ppi->appid, appid, MAX_NAME_LENGTH - 1);
+ ppi->proc_exclude = resourced_proc_excluded(appid);
if (pkgid)
- strncpy(process_info->pkgname, pkgid, MAX_NAME_LENGTH - 1);
+ strncpy(ppi->pkgname, pkgid, MAX_NAME_LENGTH - 1);
else
- extract_pkgname(process_info->appid, process_info->pkgname,
+ extract_pkgname(ppi->appid, ppi->pkgname,
MAX_NAME_LENGTH);
pthread_mutex_lock(&proc_mutex);
proc_process_list = g_slist_prepend(proc_process_list,
- process_info);
+ ppi);
pthread_mutex_unlock(&proc_mutex);
- process_info->state = PROC_STATE_DEFAULT;
}
- return process_info;
+ return ppi;
}
int proc_remove_process_list(const pid_t pid)
{
GSList *iter = NULL;
- struct proc_process_info_t *process_info = NULL;
- struct pid_info_t *found_pid = NULL;
+ struct proc_process_info_t *ppi = NULL;
+ struct pid_info_t *found = NULL;
pthread_mutex_lock(&proc_mutex);
gslist_for_each_item(iter, proc_process_list) {
- process_info = (struct proc_process_info_t *)iter->data;
- if (!process_info->pids)
+ ppi = (struct proc_process_info_t *)iter->data;
+ if (!ppi->pids)
continue;
- found_pid = find_pid_info(process_info->pids, pid);
- if(!found_pid)
+ found = find_pid_info(ppi->pids, pid);
+ if(!found)
continue;
- _D("found_pid %d", found_pid->pid);
+ _D("found_pid %d", found->pid);
+ if (ppi->main_pid == pid)
+ ppi->main_pid = 0;
/* Introduce function for removing and cleaning */
- process_info->pids = g_slist_remove(process_info->pids,
- found_pid);
- free(found_pid);
- if (!process_info->pids) {
- proc_process_list = g_slist_remove(
- proc_process_list,
- process_info);
- free(process_info);
- }
+ ppi->pids = g_slist_remove(ppi->pids,
+ found);
+ free(found);
break;
}
pthread_mutex_unlock(&proc_mutex);
return 0;
}
+int proc_delete_process_list(void)
+{
+ GSList *iter, *next;
+ GSList *pid_iter = NULL;
+ struct proc_process_info_t *ppi = NULL;
+
+ pthread_mutex_lock(&proc_mutex);
+ gslist_for_each_safe(proc_process_list, iter, next, ppi) {
+ if (ppi->pids) {
+ gslist_for_each_item(pid_iter, ppi->pids) {
+ struct pid_info_t *pi = (struct pid_info_t *)(pid_iter->data);
+ if (pi) {
+ ppi->pids = g_slist_remove(ppi->pids, pi);
+ free(pi);
+ }
+ }
+ }
+ proc_process_list = g_slist_remove(proc_process_list, ppi);
+ free(ppi);
+ }
+ pthread_mutex_unlock(&proc_mutex);
+ return 0;
+}
+
+static void proc_dump_process_list(FILE* fp)
+{
+ GSList *iter = NULL;
+ GSList *iter_pid = NULL;
+ struct proc_process_info_t *process_info = NULL;
+ int index = 0 ;
+
+ LOG_DUMP(fp, "[PROCESS LISTS]\n");
+ gslist_for_each_item(iter, proc_process_list) {
+ process_info = (struct proc_process_info_t *)iter->data;
+ LOG_DUMP(fp, "index : %d, appid : %s, pkgname : %s, main_pid : %d, type : %x\n",
+ index, process_info->appid, process_info->pkgname,
+ process_info->main_pid, process_info->type);
+ if (process_info->pids) {
+ gslist_for_each_item(iter_pid, process_info->pids) {
+ struct pid_info_t *pid_info = (struct pid_info_t *)(iter_pid->data);
+ if (pid_info) {
+ pid_t pid;
+ int oom_score_adj;
+ char appname[PROC_NAME_MAX];
+ pid = pid_info->pid;
+ if (proc_get_oom_score_adj(pid, &oom_score_adj) < 0 ||
+ proc_get_cmdline(pid, appname) < 0) {
+ process_info->pids = g_slist_remove(process_info->pids, pid_info);
+ free(pid_info);
+ continue;
+ }
+ LOG_DUMP(fp, "\t type : %s, pid : %d, command line : %s, oom_score : %d\n",
+ convert_to_proctype_str(pid_info->type), pid, appname, oom_score_adj);
+ }
+ }
+ }
+ index++;
+ }
+}
+
static void proc_free_exclude_key(gpointer data)
{
if (data)
@@ -502,18 +545,23 @@ int resourced_proc_init(const struct daemon_opts *opts)
{
int ret;
- proc_notifd = proc_noti_init( );
+ proc_notifd = proc_noti_init();
ret = proc_monitor_init();
if (ret)
_E("proc_monitor_init failed : %d", ret);
+ ret = proc_usage_stats_init();
+ if (ret)
+ _E("proc_usage_stats_init failed : %d", ret);
+
proc_exclude_init();
return ret;
}
int resourced_proc_exit(const struct daemon_opts *opts)
{
+ proc_delete_process_list();
if (proc_notifd)
close(proc_notifd);
g_hash_table_destroy(proc_exclude_list);
@@ -524,22 +572,32 @@ int resourced_proc_exit(const struct daemon_opts *opts)
void proc_set_apptype(const char *appid, const char *pkgid, int type)
{
- struct proc_process_info_t *process_info =
+ struct proc_process_info_t *ppi =
proc_create_process_list(appid, pkgid);
- if (process_info)
- process_info->type = type;
+ if (ppi)
+ ppi->type = type;
+}
+
+int proc_get_apptype(const pid_t pid)
+{
+ struct proc_process_info_t *ppi =
+ find_process_info(NULL, pid, NULL);
+
+ if (ppi) {
+ _D("get apptype = %d", ppi->type);
+ return ppi->type;
+ } else
+ _D("there is no process info for pid = %d", pid);
+ return PROC_NONE;
}
int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_name)
{
int ret = 0, oom_score_adj = 0;
- char pidbuf[32];
- struct proc_status proc_data;;
+ char pidbuf[MAX_DEC_SIZE(int)];
+ struct proc_status proc_data = {0};
if (pid && (proc_get_oom_score_adj(pid, &oom_score_adj) < 0)) {
- /* due process with pid is no longer exits
- * we need to remove it from
- * freezer_process_list */
proc_remove_process_list(pid);
_E("Empty pid or process not exists. %d", pid);
return RESOURCED_ERROR_FAIL;
@@ -552,7 +610,7 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_
proc_data.pid = pid;
proc_data.appid = app_name;
- proc_data.processinfo = NULL;
+ proc_data.ppi = NULL;
switch (type) {
case PROC_CGROUP_SET_FOREGRD:
_SD("set foreground : %d", pid);
@@ -561,7 +619,8 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_
ret = proc_set_foregrd(pid, oom_score_adj);
if (ret != 0)
return RESOURCED_ERROR_NO_DATA;
- proc_update_process_state(pid, PROC_STATE_FOREGROUND);
+ proc_data.ppi = find_process_info(app_name, pid, NULL);
+ proc_data.appid = proc_data.ppi->appid;
resourced_notify(RESOURCED_NOTIFIER_APP_FOREGRD, &proc_data);
break;
case PROC_CGROUP_SET_LAUNCH_REQUEST:
@@ -575,7 +634,7 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_
_SD("launch request %s with pkgname", pkg_name);
ret = resourced_proc_excluded(app_name);
if (!ret)
- proc_data.processinfo = proc_add_process_list(RESOURCED_APP_TYPE_GUI, pid, app_name, pkg_name);
+ proc_data.ppi = proc_add_process_list(PROC_TYPE_GUI, pid, app_name, pkg_name);
resourced_notify(RESOURCED_NOTIFIER_APP_LAUNCH, &proc_data);
_E("available memory = %u", get_available());
break;
@@ -587,29 +646,26 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_
_SD("service launch request %s, %d", app_name, pid);
if (pkg_name)
_SD("launch request %s with pkgname", pkg_name);
- proc_add_process_list(RESOURCED_APP_TYPE_SERVICE, pid, app_name, pkg_name);
+ proc_data.ppi = proc_add_process_list(PROC_TYPE_SERVICE, pid, app_name, pkg_name);
if (resourced_proc_excluded(app_name) == RESOURCED_ERROR_NONE)
resourced_notify(RESOURCED_NOTIFIER_SERVICE_LAUNCH, &proc_data);
break;
case PROC_CGROUP_SET_RESUME_REQUEST:
_SD("resume request %d", pid);
/* init oom_score_value */
- if (oom_score_adj >= OOMADJ_BACKGRD_UNLOCKED) {
- resourced_notify(RESOURCED_NOTIFIER_APP_RESUME, &proc_data);
- proc_set_oom_score_adj(pid, OOMADJ_INIT);
- }
-
if (!app_name) {
_E("need application name!pid = %d", pid);
return RESOURCED_ERROR_NO_DATA;
}
- proc_add_process_list(RESOURCED_APP_TYPE_GUI, pid, app_name, pkg_name);
- if (ret != RESOURCED_ERROR_NONE)
- _D("Failed to add to freezer list: pid %d", pid);
-
+ proc_data.ppi = proc_add_process_list(PROC_TYPE_GUI, pid, app_name, pkg_name);
+ if (oom_score_adj >= OOMADJ_BACKGRD_UNLOCKED) {
+ resourced_notify(RESOURCED_NOTIFIER_APP_RESUME, &proc_data);
+ proc_set_oom_score_adj(pid, OOMADJ_INIT);
+ }
break;
case PROC_CGROUP_SET_TERMINATE_REQUEST:
+ proc_data.ppi = find_process_info(app_name, pid, NULL);
resourced_notify(RESOURCED_NOTIFIER_APP_TERMINATE, &proc_data);
proc_remove_process_list(pid);
break;
@@ -626,7 +682,6 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name, char* pkg_
ret = proc_set_backgrd(pid, oom_score_adj);
if (ret != 0)
break;
- proc_update_process_state(pid, PROC_STATE_BACKGROUND);
break;
case PROC_CGROUP_SET_INACTIVE:
ret = proc_set_inactive(pid, oom_score_adj);
@@ -673,3 +728,16 @@ int resourced_proc_action(int type, int argnum, char **arg)
return resourced_proc_status_change(type, pid, cgroup_name, pkg_name);
}
+void resourced_proc_dump(int mode, const char *dirpath)
+{
+ char buf[PROC_BUF_MAX];
+ FILE *f = NULL;
+ if (dirpath) {
+ snprintf(buf, sizeof(buf), "%s/%s", dirpath, LOG_PREFIX);
+ f = fopen(buf, "w+");
+ }
+ proc_dump_process_list(f);
+ modules_dump((void*)f, mode);
+ if (f)
+ fclose(f);
+}
diff --git a/src/proc-stat/proc-monitor.c b/src/proc-stat/proc-monitor.c
index d97a6336..a9601f32 100644
--- a/src/proc-stat/proc-monitor.c
+++ b/src/proc-stat/proc-monitor.c
@@ -39,8 +39,6 @@
#include "lowmem-handler.h"
#include "notifier.h"
-
-
#define WATCHDOG_LAUNCHING_PARAM "WatchdogPopupLaunch"
#define WATCHDOG_KEY1 "_SYSPOPUP_CONTENT_"
#define WATCHDOG_KEY2 "_APP_NAME_"
@@ -56,6 +54,9 @@
#define SIGNAL_PROC_GROUP "ProcGroup"
#define TIZEN_DEBUG_MODE_FILE "/opt/etc/.debugmode"
+#define SIGNAL_DUMP "Dump"
+#define SIGNAL_DUMP_START "Start"
+#define SIGNAL_DUMP_FINISH "Finish"
#define INIT_PID 1
#define INIT_PROC_VAL -1
@@ -235,6 +236,8 @@ static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
char *appid;
char *pkgid;
int flags;
+ struct proc_status proc_data;;
+ struct proc_process_info_t *ppi;
ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_PRELAUNCH);
@@ -256,10 +259,13 @@ static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
_D("call proc_dbus_prelaunch_handler: appid = %s, pkgid = %s, flags = %d",
appid, pkgid, flags);
- if (flags & PROC_LARGE_HEAP) {
- proc_set_apptype(appid, pkgid, PROC_LARGE_HEAP);
+ ppi = proc_create_process_list(appid, pkgid);
+ ppi->type = flags;
+ proc_data.appid = appid;
+ proc_data.ppi = ppi;
+ resourced_notify(RESOURCED_NOTIFIER_APP_PRELAUNCH, &proc_data);
+ if (flags & PROC_LARGEMEMORY)
lowmem_dynamic_process_killer(DYNAMIC_KILL_LARGEHEAP);
- }
}
static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)
@@ -432,7 +438,7 @@ static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
int pid, childpid, ret;
if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_GROUP) == 0) {
- _D("there is no watchdog result signal");
+ _D("there is no process group signal");
return;
}
@@ -445,10 +451,44 @@ static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
_D("there is no message");
return;
}
-
+ _D("received process grouping : owner %d, child %d", pid, childpid);
proc_set_group(pid, childpid);
}
+static void send_dump_signal(char *signal)
+{
+ pid_t pid = getpid();
+
+ broadcast_edbus_signal(DUMP_SERVICE_OBJECT_PATH,
+ DUMP_SERVICE_INTERFACE_NAME, signal, DBUS_TYPE_INT32, &pid);
+}
+
+static void proc_dbus_dump_handler(void *data, DBusMessage *msg)
+{
+ DBusError err;
+ dbus_bool_t ret;
+ char *path;
+ int mode;
+
+ if (dbus_message_is_signal(msg, DUMP_SERVICE_INTERFACE_NAME, SIGNAL_DUMP) == 0) {
+ _D("there is no process group signal");
+ return;
+ }
+
+ dbus_error_init(&err);
+
+ ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &mode,
+ DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID);
+ if (ret == 0) {
+ _D("there is no message");
+ return;
+ }
+ _D("received dump request : path %s", path);
+ send_dump_signal(SIGNAL_DUMP_START);
+ resourced_proc_dump(mode, path);
+ send_dump_signal(SIGNAL_DUMP_FINISH);
+}
+
static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
{
DBusMessage *reply;
@@ -520,41 +560,44 @@ static resourced_ret_c proc_dbus_init(void)
{
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_WATCHDOG_RESULT,
- proc_dbus_watchdog_result);
+ proc_dbus_watchdog_result, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_ACTIVE,
- proc_dbus_active_signal_handler);
+ proc_dbus_active_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_EXCLUDE,
- proc_dbus_exclude_signal_handler);
+ proc_dbus_exclude_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_PRELAUNCH,
- proc_dbus_prelaunch_signal_handler);
+ proc_dbus_prelaunch_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_STATUS,
- proc_dbus_proc_signal_handler);
+ proc_dbus_proc_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_SWEEP,
- proc_dbus_sweep_signal_handler);
+ proc_dbus_sweep_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_WATCHDOG,
- proc_dbus_watchdog_handler);
+ proc_dbus_watchdog_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
- SIGNAL_PROC_WATCHDOG,
- proc_dbus_grouping_handler);
+ SIGNAL_PROC_GROUP,
+ proc_dbus_grouping_handler, NULL);
register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
- DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on);
+ DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on, NULL);
register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
- DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off);
+ DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off, NULL);
+
+ register_edbus_signal_handler(DUMP_SERVICE_OBJECT_PATH,
+ DUMP_SERVICE_INTERFACE_NAME, SIGNAL_DUMP, proc_dbus_dump_handler, NULL);
/* start watchdog check timer for preveting ANR during booting */
watchdog_check_timer =
diff --git a/src/proc-stat/proc-process.c b/src/proc-stat/proc-process.c
index a299bcfe..bd2445de 100644
--- a/src/proc-stat/proc-process.c
+++ b/src/proc-stat/proc-process.c
@@ -35,7 +35,6 @@
#include "lowmem-common.h"
#include "logging-common.h"
#include "macro.h"
-#include "swap-common.h"
#include "proc-noti.h"
#include "notifier.h"
@@ -49,116 +48,91 @@ enum proc_background_type {
PROC_BACKGROUND_ACTIVE,
};
-static int proc_backgrd_manage(int currentpid, int active)
+int proc_set_service_oomscore(const pid_t pid, const int oom_score)
{
- int pid = -1, pgid, ret;
+ int service_oom;
+ if (oom_score > 0)
+ service_oom = oom_score - OOMADJ_SERVICE_GAP;
+ else
+ service_oom = OOMADJ_SERVICE_DEFAULT;
+ return proc_set_oom_score_adj(pid, service_oom);
+}
+
+static int proc_backgrd_manage(int currentpid, int active, int oom_score_adj)
+{
+ int pid = -1, ret, flag = RESOURCED_NOTIFIER_APP_BACKGRD;
struct proc_status proc_data;;
- DIR *dp;
- struct dirent *dentry;
FILE *fp;
char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
- char appname[PROC_NAME_MAX];
- int count = 0;
- int candidatepid[16] = {0,};
- int cur_oom = -1, prev_oom=OOMADJ_BACKGRD_UNLOCKED, select_pid=0;
+ int cur_oom = -1;
static int checkprevpid = 0;
- unsigned long swap_args[2] = {0,};
- unsigned long logging_args[3] = {0,};
-
- ret = proc_get_cmdline(currentpid, appname);
- if (ret == RESOURCED_ERROR_NONE) {
- ret = resourced_proc_excluded(appname);
- if (!active && !ret) {
- proc_data.pid = currentpid;
- proc_data.appid = appname;
- resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD, &proc_data);
- }
- if (ret) {
- _D("BACKGRD MANAGE : don't manage background application by %d", currentpid);
- return RESOURCED_ERROR_NONE;
- }
- }
+ GSList *iter;
+ struct proc_process_info_t *ppi =
+ find_process_info(NULL, currentpid, NULL);
- dp = opendir("/proc");
- if (!dp) {
- _E("BACKGRD MANAGE : fail to open /proc");
- return RESOURCED_ERROR_FAIL;
+ if (!ppi || ppi->proc_exclude) {
+ _D("BACKGRD MANAGE : don't manage background application by %d", currentpid);
+ return RESOURCED_ERROR_NONFREEZABLE;
}
- while ((dentry = readdir(dp)) != NULL) {
-
- if (!isdigit(dentry->d_name[0]))
- continue;
-
- pid = atoi(dentry->d_name);
- pgid = getpgid(pid);
- if (!pgid)
- continue;
-
- snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
- fp = fopen(buf, "r+");
- if (fp == NULL)
- continue;
- if (fgets(buf, sizeof(buf), fp) == NULL) {
- fclose(fp);
- continue;
- }
- cur_oom = atoi(buf);
-
- logging_args[0] = (unsigned long)pid;
- logging_args[1] = (unsigned long)pgid;
- logging_args[2] = (unsigned long)cur_oom;
- logging_control(LOGGING_INSERT_PROC_LIST, logging_args);
-
- if (currentpid != pid && currentpid == pgid) {
- proc_set_group(currentpid, pid);
- fclose(fp);
- continue;
- }
-
- if (active || checkprevpid == currentpid) {
- fclose(fp);
- continue;
- }
- if (select_pid != pid && select_pid == pgid && count < 16)
- {
- _D("found candidate child pid = %d, pgid = %d", pid, pgid);
- candidatepid[count++] = pid;
- fclose(fp);
- continue;
- }
+ proc_data.pid = currentpid;
+ proc_data.appid = ppi->appid;
+ proc_data.ppi = ppi;
+ if (active)
+ flag = RESOURCED_NOTIFIER_APP_BACKGRD_ACTIVE;
+ resourced_notify(flag, &proc_data);
+
+ if (active)
+ return RESOURCED_ERROR_NONE;
+
+ if (checkprevpid != currentpid) {
+ gslist_for_each_item(iter, proc_process_list) {
+ struct proc_process_info_t *spi = (struct proc_process_info_t *)iter->data;
+ if (!spi->pids || !spi->main_pid)
+ continue;
- swap_args[0] = (unsigned long)pid;
- if (cur_oom > OOMADJ_BACKGRD_UNLOCKED && cur_oom > prev_oom
- && !swap_status(SWAP_CHECK_PID, swap_args)) {
- count = 0;
- candidatepid[count++] = pid;
- select_pid = pid;
- prev_oom = cur_oom;
- }
+ pid = spi->main_pid;
+ snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
+ fp = fopen(buf, "r+");
+ if (fp == NULL) {
+ spi->main_pid = 0;
+ continue;
+ }
+ if (fgets(buf, sizeof(buf), fp) == NULL) {
+ fclose(fp);
+ spi->main_pid = 0;
+ continue;
+ }
+ cur_oom = atoi(buf);
- if (cur_oom >= OOMADJ_APP_MAX) {
+ if (cur_oom >= OOMADJ_APP_MAX) {
+ fclose(fp);
+ continue;
+ } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
+ _D("BACKGRD : process %d set score %d (before %d)",
+ pid, cur_oom+OOMADJ_APP_INCREASE, cur_oom);
+ fprintf(fp, "%d", cur_oom+OOMADJ_APP_INCREASE);
+ }
fclose(fp);
- continue;
- } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
- _D("BACKGRD : process %d set score %d (before %d)",
- pid, cur_oom+OOMADJ_APP_INCREASE, cur_oom);
- fprintf(fp, "%d", cur_oom+OOMADJ_APP_INCREASE);
}
- fclose(fp);
}
- if (select_pid) {
- _D("found candidate pid = %d, count = %d", candidatepid, count);
- swap_args[0] = (unsigned long)candidatepid;
- swap_args[1] = (unsigned long)count;
- resourced_notify(RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID, swap_args);
+ gslist_for_each_item(iter, ppi->pids) {
+ struct pid_info_t *pi = (struct pid_info_t *)(iter->data);
+ if (pi) {
+ if (pi->type == PROC_TYPE_SERVICE)
+ ret = proc_set_service_oomscore(pi->pid, oom_score_adj);
+ else if (pi->type == PROC_TYPE_GUI && ppi->main_pid != pi->pid)
+ continue;
+ else
+ ret = proc_set_oom_score_adj(pi->pid, oom_score_adj);
+ if (ret < 0) {
+ ppi->pids = g_slist_remove(ppi->pids, pi);
+ free(pi);
+ }
+ }
}
checkprevpid = currentpid;
- closedir(dp);
-
- logging_control(LOGGING_UPDATE_PROC_INFO, NULL);
-
return RESOURCED_ERROR_NONE;
}
@@ -166,17 +140,22 @@ static int proc_foregrd_manage(int pid, int oom_score_adj)
{
int ret = 0;
GSList *iter;
- struct proc_process_info_t *process_info =
+ struct proc_process_info_t *ppi =
find_process_info(NULL, pid, NULL);
- if (!process_info) {
- ret = proc_set_oom_score_adj(pid, oom_score_adj);
- return ret;
+ if (!ppi) {
+ proc_set_oom_score_adj(pid, oom_score_adj);
+ return RESOURCED_ERROR_NO_DATA;
}
- gslist_for_each_item(iter, process_info->pids) {
- struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
- ret = proc_set_oom_score_adj(pid_info->pid, oom_score_adj);
+ gslist_for_each_item(iter, ppi->pids) {
+ struct pid_info_t *pi = (struct pid_info_t *)(iter->data);
+ if (pi->type == PROC_TYPE_SERVICE)
+ ret = proc_set_service_oomscore(pi->pid, oom_score_adj);
+ else if (pi->type == PROC_TYPE_GUI && ppi->main_pid != pi->pid)
+ continue;
+ else
+ ret = proc_set_oom_score_adj(pi->pid, oom_score_adj);
}
return ret;
}
@@ -219,8 +198,6 @@ int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
{
pid_t pid = -1;
int count=0, ret;
- DIR *dp;
- struct dirent *dentry;
FILE *fp;
gint *piddata;
char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
@@ -228,11 +205,9 @@ int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
int cur_oom = -1;
int select_sweep_limit;
- dp = opendir("/proc");
- if (!dp) {
- _E("BACKGRD MANAGE : fail to open /proc");
- return RESOURCED_ERROR_FAIL;
- }
+ GSList *iter;
+ struct proc_process_info_t *ppi;
+
if (proc_sweep_timer)
ecore_timer_del(proc_sweep_timer);
if (proc_sweep_list)
@@ -244,13 +219,12 @@ int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
else
select_sweep_limit = OOMADJ_BACKGRD_LOCKED;
- while ((dentry = readdir(dp)) != NULL) {
- if (!isdigit(dentry->d_name[0]))
+ gslist_for_each_item(iter, proc_process_list) {
+ ppi = (struct proc_process_info_t *)iter->data;
+ if (!ppi->pids || !ppi->main_pid || callpid == ppi->main_pid)
continue;
- pid = atoi(dentry->d_name);
- if (pid == callpid)
- continue;
+ pid = ppi->main_pid;
snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
fp = fopen(buf, "r+");
@@ -282,7 +256,6 @@ int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
proc_sweep_timer =
ecore_timer_add(PROC_SWEEP_TIMER, proc_check_sweep_cb, (void *)proc_sweep_list);
}
- closedir(dp);
return count;
}
@@ -384,7 +357,7 @@ int proc_set_foregrd(pid_t pid, int oom_score_adj)
break;
default:
if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
- ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
+ ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED);
} else {
ret = -1;
}
@@ -405,12 +378,10 @@ int proc_set_backgrd(int pid, int oom_score_adj)
ret = -1;
break;
case OOMADJ_FOREGRD_LOCKED:
- proc_backgrd_manage(pid, PROC_BACKGROUND_ACTIVE);
- ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
+ ret = proc_backgrd_manage(pid, PROC_BACKGROUND_ACTIVE, OOMADJ_BACKGRD_LOCKED);
break;
case OOMADJ_FOREGRD_UNLOCKED:
- proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE);
- ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
+ ret = proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE, OOMADJ_BACKGRD_UNLOCKED);
break;
case OOMADJ_INIT:
ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
@@ -434,10 +405,10 @@ int proc_set_active(int pid, int oom_score_adj)
case OOMADJ_FOREGRD_LOCKED:
case OOMADJ_BACKGRD_LOCKED:
case OOMADJ_SU:
- case OOMADJ_INIT:
/* don't change oom value pid */
ret = -1;
break;
+ case OOMADJ_INIT:
case OOMADJ_FOREGRD_UNLOCKED:
ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
break;
@@ -461,7 +432,7 @@ int proc_set_active(int pid, int oom_score_adj)
int proc_set_inactive(int pid, int oom_score_adj)
{
int ret = 0;
- struct proc_process_info_t * processinfo;
+ struct proc_process_info_t * ppi;
switch (oom_score_adj) {
case OOMADJ_FOREGRD_UNLOCKED:
case OOMADJ_BACKGRD_UNLOCKED:
@@ -474,8 +445,8 @@ int proc_set_inactive(int pid, int oom_score_adj)
ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
break;
case OOMADJ_BACKGRD_LOCKED:
- processinfo = find_process_info(NULL, pid, NULL);
- if (processinfo)
+ ppi = find_process_info(NULL, pid, NULL);
+ if (ppi)
ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
break;
case OOMADJ_SERVICE_FOREGRD:
@@ -496,15 +467,15 @@ int proc_set_inactive(int pid, int oom_score_adj)
void proc_set_group(pid_t onwerpid, pid_t childpid)
{
int oom_score_adj = 0;
- struct proc_process_info_t *process_info =
+ struct proc_process_info_t *ppi =
find_process_info(NULL, onwerpid, NULL);
if (proc_get_oom_score_adj(onwerpid, &oom_score_adj) < 0) {
_D("owner pid(%d) was already terminated", onwerpid);
return;
}
- if (process_info) {
- proc_add_pid_list(process_info, childpid, RESOURCED_APP_TYPE_GROUP);
+ if (ppi) {
+ proc_add_pid_list(ppi, childpid, PROC_TYPE_GROUP);
proc_set_oom_score_adj(childpid, oom_score_adj);
}
}
diff --git a/src/proc-stat/proc-usage-stats-helper.c b/src/proc-stat/proc-usage-stats-helper.c
new file mode 100644
index 00000000..a5a96e5c
--- /dev/null
+++ b/src/proc-stat/proc-usage-stats-helper.c
@@ -0,0 +1,256 @@
+/*
+ * 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 proc-usage-stats-helper.c
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "proc-usage-stats-helper.h"
+#include "macro.h"
+#include "trace.h"
+
+#define BtoKiB(bytes) (bytes >> 10)
+#define kBtoKiB(kbytes) (int)(((long long)kbytes * 1024)/1000)
+
+#define TASK_NAME_BASE "runtime_info_%s_usage"
+
+static int proc_get_virtual_mem_size(int pid, int *vsize)
+{
+ FILE *proc_stat;
+ char buf[1024];
+ unsigned long vsz;
+
+ proc_stat = NULL;
+
+ if (!vsize)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+ proc_stat = fopen(buf, "r");
+ if (!proc_stat)
+ goto error;
+
+ while (fgets(buf, sizeof(buf), proc_stat) != NULL) {
+ if (sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %lu",
+ &vsz) != 1)
+ goto error;
+ }
+ fclose(proc_stat);
+
+ *vsize = BtoKiB(vsz);
+ return RESOURCED_ERROR_NONE;
+
+error:
+ if (proc_stat)
+ fclose(proc_stat);
+ _E("error reading /proc/%d/stat file", pid);
+ return RESOURCED_ERROR_FAIL;
+}
+
+static int proc_get_smaps_info(int pid, struct process_memory_info_s *mem_info)
+{
+ FILE *smaps;
+ char buf[1024];
+ int value;
+
+ smaps = NULL;
+
+ if (!mem_info)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/smaps", pid);
+ smaps = fopen(buf, "r");
+ if (!smaps)
+ goto error;
+
+ while (fgets(buf, sizeof(buf), smaps) != NULL) {
+ if (sscanf(buf, "Rss: %d kB", &value) == 1)
+ mem_info->rss += kBtoKiB(value);
+ else if (sscanf(buf, "Pss: %d kB", &value) == 1)
+ mem_info->pss += kBtoKiB(value);
+ else if (sscanf(buf, "Shared_Clean: %d kB", &value) == 1)
+ mem_info->shared_clean += kBtoKiB(value);
+ else if (sscanf(buf, "Shared_Dirty: %d kB", &value) == 1)
+ mem_info->shared_dirty += kBtoKiB(value);
+ else if (sscanf(buf, "Private_Clean: %d kB", &value) == 1)
+ mem_info->private_clean += kBtoKiB(value);
+ else if (sscanf(buf, "Private_Dirty: %d kB", &value) == 1)
+ mem_info->private_dirty += kBtoKiB(value);
+ }
+ fclose(smaps);
+
+ return RESOURCED_ERROR_NONE;
+
+error:
+ if (smaps)
+ fclose(smaps);
+ _E("error reading /proc/%d/smaps file", pid);
+ return RESOURCED_ERROR_FAIL;
+}
+
+/* Helper functions to get the needed memory usage info. */
+void proc_get_memory_usage(int pid, struct process_memory_info_s *mem_info)
+{
+ if (!mem_info)
+ return;
+
+ if (pid < 0)
+ goto error;
+
+ memset(mem_info, 0, sizeof(struct process_memory_info_s));
+ if (proc_get_virtual_mem_size(pid, &mem_info->vsz) != RESOURCED_ERROR_NONE)
+ goto error;
+
+ if (proc_get_smaps_info(pid, mem_info) != RESOURCED_ERROR_NONE)
+ goto error;
+
+ return;
+
+error:
+ mem_info->vsz = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->rss = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->pss = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->shared_clean = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->shared_dirty = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->private_clean = INVALID_PROCESS_INFO_FIELD_VALUE;
+ mem_info->private_dirty = INVALID_PROCESS_INFO_FIELD_VALUE;
+}
+
+/* Helper functions to get the needed cpu usage info. */
+void proc_get_cpu_usage(int pid, struct process_cpu_usage_s *cpu_usage)
+{
+ unsigned long utime, stime;
+ FILE *proc_stat;
+ char buf[1024];
+
+ proc_stat = NULL;
+
+ if (!cpu_usage)
+ return;
+
+ if (pid < 0)
+ goto error;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
+ proc_stat = fopen(buf, "r");
+ if (!proc_stat)
+ goto error;
+ while (fgets(buf, sizeof(buf), proc_stat) != NULL) {
+ if (sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %lu %lu",
+ &utime, &stime) != 2) {
+ goto error;
+ }
+ }
+ fclose(proc_stat);
+
+ cpu_usage->utime = (int)utime;
+ cpu_usage->stime = (int)stime;
+ return;
+
+error:
+ if (proc_stat)
+ fclose(proc_stat);
+ _E("error reading /proc/%d/stat file", pid);
+ cpu_usage->utime = INVALID_PROCESS_INFO_FIELD_VALUE;
+ cpu_usage->stime = INVALID_PROCESS_INFO_FIELD_VALUE;
+}
+
+/* Helper function to read from usage_info struct and populate
+ * result according to the task type */
+int proc_read_from_usage_struct(void *usage_info_list, int index,
+ int *result, runtime_info_task_type type)
+{
+ if (!usage_info_list || !result || (index < 0)) {
+ _E("invalid input");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ if (type == RUNTIME_INFO_TASK_MEMORY) {
+ struct process_memory_info_s *mem_info;
+
+ mem_info = (struct process_memory_info_s *)usage_info_list;
+ result[0] = mem_info[index].vsz;
+ result[1] = mem_info[index].rss;
+ result[2] = mem_info[index].pss;
+ result[3] = mem_info[index].shared_clean;
+ result[4] = mem_info[index].shared_dirty;
+ result[5] = mem_info[index].private_clean;
+ result[6] = mem_info[index].private_dirty;
+ } else {
+ struct process_cpu_usage_s *cpu_usage;
+
+ cpu_usage = (struct process_cpu_usage_s *)usage_info_list;
+ result[0] = cpu_usage[index].utime;
+ result[1] = cpu_usage[index].stime;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+/* Create task name according to the current time and
+ * set it to the input param task_name */
+void proc_get_task_name(char *task_name, int size,
+ runtime_info_task_type task_type)
+{
+ struct tm cur_tm;
+ time_t now;
+ char buf[TASK_NAME_SIZE];
+
+ snprintf(buf, sizeof(buf), TASK_NAME_BASE,
+ ((task_type == RUNTIME_INFO_TASK_MEMORY) ? "memory" : "cpu"));
+
+ if (!task_name || size <= 0)
+ return;
+
+ now = time(NULL);
+ if (localtime_r(&now, &cur_tm) == NULL) {
+ _E("Failed to get localtime");
+ snprintf(task_name, size, "%s_%llu",
+ buf, (long long)now);
+ return;
+ }
+
+ snprintf(task_name, size, "%s_%.4d%.2d%.2d_%.2d%.2d%.2d",
+ buf, (1900 + cur_tm.tm_year),
+ 1 + cur_tm.tm_mon, cur_tm.tm_mday, cur_tm.tm_hour,
+ cur_tm.tm_min, cur_tm.tm_sec);
+}
+
+/* Helper function to free the runtime info task instance */
+void proc_free_runtime_info_task(struct runtime_info_task *rt_task)
+{
+ if (!rt_task)
+ return;
+
+ if (rt_task->usage_info_list)
+ free(rt_task->usage_info_list);
+
+ close(rt_task->pipe_fds[0]);
+ close(rt_task->pipe_fds[1]);
+
+ dbus_message_unref(rt_task->task_msg);
+
+ free(rt_task);
+}
diff --git a/src/proc-stat/proc-usage-stats.c b/src/proc-stat/proc-usage-stats.c
new file mode 100644
index 00000000..bb6ce2e5
--- /dev/null
+++ b/src/proc-stat/proc-usage-stats.c
@@ -0,0 +1,378 @@
+/*
+ * 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 proc-usage-stats.c
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * ** Handles the dbus method calls made by the runtime-info APIs
+ * ** The supported calls are for collection of memory and cpu usage of input processes
+ * ** The fields collected can be found in the process_memory_info_s and
+ * process_cpu_usage_s structs in the proc-usage-stats-helper.h file
+ * ** The working is as follows:
+ * * The dbus method is called from runtime-info API
+ * * For each request, a runtime_info_task instance is created
+ * * This instance contains info related to that request
+ * * A pipe is created for each request and an ecore handler is added for the read end
+ * * A thread is swapned for the request and this thread collects the needed info
+ * * After collection of the usage info, the thread writes the success status to the
+ * write end of the pipe
+ * * This activates the handler, which appends the collected usage info to the reply
+ * dbus message and sends it to the process making the method call
+ * * The reply message is as follows:
+ * * If everything succeeded, it is an array of memory or cpu usage info structs
+ * * If some of the PIDs are invalid, then the entries for those PIDs will be
+ * INVALID_PROCESS_FIELD_VALUE
+ * * If anything went wrong in the above steps, then the reply is an integer
+ * which contains the error value
+ * * In case there was any error writing to the pipe from the swapned thread,
+ * then there is no reply and the method call fails after the timeout
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <Ecore.h>
+#include <errno.h>
+
+#include "proc-usage-stats.h"
+#include "proc-usage-stats-helper.h"
+#include "resourced.h"
+#include "macro.h"
+#include "trace.h"
+#include "edbus-handler.h"
+
+#define BtoKiB(bytes) (bytes >> 10)
+#define kBtoKiB(kbytes) (int)(((long long)kbytes * 1024)/1000)
+
+#define PROCESS_MEMORY_USAGE_METHOD "ProcMemoryUsage"
+#define PROCESS_CPU_USAGE_METHOD "ProcCpuUsage"
+
+/**
+ * @brief DBus method to return the memory usage information of input processes
+ * @since_tizen 2.4
+ *
+ * @param[in] obj The E_DBus_Object
+ * @param[in] msg The dbus message sent by the runtime info API.
+ * This should be an array of process IDs.
+ *
+ * @retval The response dbus message contains an array of structs
+ * (structure similar to process_memory_info_s). The structs contain the
+ * memory usage info fields for the processes (in the same order).
+ * For invalid process IDs, the fields of the process_memory_info_s struct
+ * will be set to INVALID_PROCESS_INFO_FIELD_VALUE.
+ * If the input dbus message does not contain array of integers or if there
+ * are errors in computation, collection and sending of usage info, then the
+ * response dbus message contains only an integer whose value will the error value.
+ */
+static DBusMessage *edbus_proc_memory_usage(E_DBus_Object *obj, DBusMessage *msg);
+
+/**
+ * @brief DBus method to return the cpu usage information of input processes
+ * @since_tizen 2.4
+ *
+ * @param[in] obj The E_DBus_Object
+ * @param[in] msg The dbus message sent by the runtime info API.
+ * This should be an array of process IDs.
+ *
+ * @retval The response dbus message contains an array of structs
+ * (structure similar to process_cpu_usage_s). The structs contain the
+ * cpu usage info fields for the processes (in the same order).
+ * For invalid process IDs, the fields of the process_cpu_usage_s struct
+ * will be set to INVALID_PROCESS_INFO_FIELD_VALUE.
+ * If the input dbus message does not contain array of integers or if there
+ * are errors in computation, collection and sending of usage info, then the
+ * response dbus message contains only an integer whose value will the error value.
+ */
+static DBusMessage *edbus_proc_cpu_usage(E_DBus_Object *obj, DBusMessage *msg);
+
+/* edbus_methods to register with edbus */
+static const struct edbus_method edbus_methods[] = {
+ { PROCESS_MEMORY_USAGE_METHOD, "ai", NULL, edbus_proc_memory_usage },
+ { PROCESS_CPU_USAGE_METHOD, "ai", NULL, edbus_proc_cpu_usage },
+};
+
+/* Ecore file handler for the read end of the pipe.
+ * Receives the error status from the runtime info task thread and collects
+ * the usage info calculated and sends it in a dbus message or send an error dbus message back
+ * with the error status added to the message
+ */
+static Eina_Bool proc_runtime_info_task_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+ int i, j, ret, rsize, struct_size;
+ int fd;
+ int result[7];
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_arr, iter_struct;
+ struct runtime_info_task *rt_task;
+
+ /* In case of errors in ecore file hander, the returned dbus message
+ * contains only a failure value */
+ rt_task = (struct runtime_info_task *)data;
+ if (!rt_task) {
+ _E("invalid input data");
+ goto error;
+ }
+
+ if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
+ _E("task %s: ecore_main_fd_handler_active_get_error", rt_task->task_name);
+ goto error;
+ }
+
+ fd = ecore_main_fd_handler_fd_get(fd_handler);
+ if (fd < 0) {
+ _E("task %s: ecore_main_fd_handler_fd_get error", rt_task->task_name);
+ goto error;
+ }
+
+ rsize = read(fd, &ret, sizeof(int));
+ if (rsize != sizeof(int)) {
+ _E("task %s: error reading value from read end of pipe", rt_task->task_name);
+ goto error;
+ }
+ _D("task %s: received %d on the read end", rt_task->task_name, ret);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("task %s: error in collection of information", rt_task->task_name);
+ goto error;
+ }
+
+ /* Create a reply message with the needed structure */
+ reply = dbus_message_new_method_return(rt_task->task_msg);
+ if (!reply) {
+ _E("task %s: out of memory to allocate for reply dbus message. not attempting again!!!", rt_task->task_name);
+ return ECORE_CALLBACK_CANCEL;
+ }
+ dbus_message_iter_init_append(reply, &iter);
+ if (rt_task->task_type == RUNTIME_INFO_TASK_MEMORY) {
+ struct_size = 7;
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(iiiiiii)", &iter_arr);
+ } else {
+ struct_size = 2;
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ii)", &iter_arr);
+ }
+ /* Populate the reply message with the usage info */
+ for (i = 0; i < rt_task->task_size; ++i) {
+ dbus_message_iter_open_container(&iter_arr, DBUS_TYPE_STRUCT, NULL, &iter_struct);
+
+ /* Write the fields of the usage info struct to an int array
+ * (this is so that the code of dbus message append could be more elegant) */
+ ret = proc_read_from_usage_struct(rt_task->usage_info_list, i, result, rt_task->task_type);
+ if (ret != RESOURCED_ERROR_NONE) {
+ _E("task %s: error in reading from usage info struct", rt_task->task_name);
+ goto error;
+ }
+
+ for (j = 0; j < struct_size; ++j)
+ dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_INT32, &result[j]);
+
+ dbus_message_iter_close_container(&iter_arr, &iter_struct);
+ }
+ dbus_message_iter_close_container(&iter, &iter_arr);
+ goto send_message;
+
+error:
+ /* In case of error, return only a failure value in the reply dbus message */
+ _D("task %s: error occured in collection of usage info, sending error message", rt_task->task_name);
+ reply = dbus_message_new_method_return(rt_task->task_msg);
+ ret = -EREMOTEIO;
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+send_message:
+ /* Send the reply message back to the caller. Best effort feature. */
+ _D("task %s: sending reply dbus message", rt_task->task_name);
+ ret = edbus_message_send(reply);
+ if (ret != RESOURCED_ERROR_NONE)
+ _E("task %s: sending message failed. not attempting again!!!", rt_task->task_name);
+
+ proc_free_runtime_info_task(rt_task);
+ dbus_message_unref(reply);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static int proc_runtime_info_task(struct runtime_info_task *rt_task)
+{
+ int i, ret;
+ int wsize;
+
+ /* Populate the usage_info_list with the needed info. There can be no failures here. */
+ if (rt_task->task_type == RUNTIME_INFO_TASK_MEMORY) {
+ struct process_memory_info_s *mem_info;
+
+ mem_info = (struct process_memory_info_s *)rt_task->usage_info_list;
+ for (i = 0; i < rt_task->task_size; ++i)
+ proc_get_memory_usage(rt_task->pid_list[i], &mem_info[i]);
+ } else {
+ struct process_cpu_usage_s *cpu_usage;
+
+ cpu_usage = (struct process_cpu_usage_s *)rt_task->usage_info_list;
+ for (i = 0; i < rt_task->task_size; ++i)
+ proc_get_cpu_usage(rt_task->pid_list[i], &cpu_usage[i]);
+ }
+
+ /* Write to the write end of the pipe depending on the success of
+ * the info collection (currently this is always success) */
+ ret = RESOURCED_ERROR_NONE;
+ wsize = write(rt_task->pipe_fds[1], &ret, sizeof(int));
+ if (wsize != sizeof(int)) {
+ _E("task %s: error in writing to write end of pipe", rt_task->task_name);
+ return RESOURCED_ERROR_FAIL;
+ }
+ return RESOURCED_ERROR_NONE;
+}
+
+/* Task thread start routine. Gathers needed info and writes it to
+ * the memory in the runtime_info_task instance.
+ */
+static void *proc_runtime_info_task_thread(void *arg)
+{
+ int ret;
+ struct runtime_info_task *rt_task = (struct runtime_info_task *)arg;
+
+ if (!rt_task) {
+ _E("invalid arguments!");
+ return NULL;
+ }
+
+ ret = proc_runtime_info_task(rt_task);
+ _D("task %s: finished processing, task status %d", rt_task->task_name, ret);
+
+ if (ret != RESOURCED_ERROR_NONE) {
+ /* TODO: write code to close fds and release the runtime_task_info memory */
+ _E("task %s: request was not completed! no reply to be sent to runtime-info!!!", rt_task->task_name);
+ }
+
+ return NULL;
+}
+
+static DBusMessage *proc_runtime_info_request_handler(DBusMessage *msg, runtime_info_task_type type)
+{
+ int ret;
+ pthread_t task_thread;
+ struct runtime_info_task *rt_task;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusError err;
+ dbus_bool_t bret;
+ Ecore_Fd_Handler *task_efd;
+
+ rt_task = NULL;
+
+ dbus_message_iter_init(msg, &iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_INT32) {
+ _E("wrong message arguments. expected array of integers");
+ ret = -EIO;
+ goto error;
+ }
+
+ /* Create runtime_info_task for current task */
+ rt_task = (struct runtime_info_task *)malloc(sizeof(struct runtime_info_task));
+ if (!rt_task) {
+ _E("out of memory: not able to create runtime_info_task");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Populate fields of the runtime_info_task */
+ proc_get_task_name(rt_task->task_name, sizeof(rt_task->task_name),
+ type);
+ rt_task->task_type = type;
+ dbus_message_ref(msg);
+ rt_task->task_msg = msg;
+
+ _D("Received %s usage request, task name is %s",
+ (rt_task->task_type == RUNTIME_INFO_TASK_MEMORY) ? "memory" : "cpu",
+ rt_task->task_name);
+
+ dbus_error_init(&err);
+ bret = dbus_message_get_args(rt_task->task_msg, &err, DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
+ &rt_task->pid_list, &rt_task->task_size, DBUS_TYPE_INVALID);
+ if (!bret) {
+ _E("task %s: not able to extract list of process IDs from the dbus message", rt_task->task_name);
+ ret = -EIO;
+ goto error;
+ }
+
+ rt_task->usage_info_list = NULL;
+ if (rt_task->task_type == RUNTIME_INFO_TASK_MEMORY)
+ rt_task->usage_info_list = (void *)malloc(sizeof(struct process_memory_info_s) * rt_task->task_size);
+ else
+ rt_task->usage_info_list = (void *)malloc(sizeof(struct process_cpu_usage_s) * rt_task->task_size);
+ if (!rt_task->usage_info_list) {
+ _E("task %s: out of memory: not able to create usage_info_list of rt_task", rt_task->task_name);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* Create pipe between main loop and (to-be-created) task thread and add ecore file handler for the read end */
+ ret = pipe(rt_task->pipe_fds);
+ if (ret) {
+ _E("task %s: error creating pipe.", rt_task->task_name);
+ ret = -EIO;
+ goto error;
+ }
+ task_efd = ecore_main_fd_handler_add(rt_task->pipe_fds[0], ECORE_FD_READ,
+ (Ecore_Fd_Cb)proc_runtime_info_task_cb, (void *)rt_task, NULL, NULL);
+ if (!task_efd) {
+ _E("task %s: error creating ecore file handler", rt_task->task_name);
+ ret = -EREMOTEIO;
+ goto error;
+ }
+
+ /* Create task thread to complete requested task */
+ ret = pthread_create(&task_thread, NULL, (void *)proc_runtime_info_task_thread, (void *)rt_task);
+ if (ret) {
+ _E("task %s: error creating task thread", rt_task->task_name);
+ ret = -EREMOTEIO;
+ goto error;
+ } else
+ pthread_detach(task_thread);
+ _D("task %s: created thread for task", rt_task->task_name);
+ dbus_error_free(&err);
+ return NULL;
+
+error:
+ /* In case of error, return only a failure value in the reply dbus message */
+ _D("task %s: error occured, sending error reply message", rt_task->task_name);
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+
+ dbus_error_free(&err);
+ proc_free_runtime_info_task(rt_task);
+ return reply;
+}
+
+static DBusMessage *edbus_proc_memory_usage(E_DBus_Object *obj, DBusMessage *msg)
+{
+ return proc_runtime_info_request_handler(msg, RUNTIME_INFO_TASK_MEMORY);
+}
+
+static DBusMessage *edbus_proc_cpu_usage(E_DBus_Object *obj, DBusMessage *msg)
+{
+ return proc_runtime_info_request_handler(msg, RUNTIME_INFO_TASK_CPU);
+}
+
+resourced_ret_c proc_usage_stats_init(void)
+{
+ int ret;
+
+ ret = edbus_add_methods(RESOURCED_PATH_PROCESS, edbus_methods, ARRAY_SIZE(edbus_methods));
+ return ret;
+}
diff --git a/src/resourced/init.c b/src/resourced/init.c
index 0b1dc8d9..34cdfb2a 100644
--- a/src/resourced/init.c
+++ b/src/resourced/init.c
@@ -42,7 +42,6 @@
static struct daemon_opts opts = { 1,
1,
- 1,
COUNTER_UPDATE_PERIOD,
FLUSH_PERIOD,
RESOURCED_DEFAULT_STATE,
@@ -153,19 +152,16 @@ static void sig_term_handler(int sig)
{
struct shared_modules_data *shared_data = get_shared_modules_data();
- opts.state |= RESOURCED_FORCIBLY_QUIT_STATE;
_SD("sigterm or sigint received");
if (shared_data && shared_data->carg && shared_data->carg->ecore_timer) {
+ SET_BIT(shared_data->carg->opts->state, RESOURCED_FORCIBLY_QUIT_STATE);
/* save data on exit, it's impossible to do in fini
* module function, due it executes right after ecore stopped */
+#ifdef NETWORK_MODULE
reschedule_count_timer(shared_data->carg, 0);
-
- /* Another way it's introduce another timer and quit main loop
- * in it with waiting some event. */
- sleep(TIME_TO_SAFE_DATA);
+#endif
+ ecore_timer_thaw(shared_data->darg->ecore_quit);
}
-
- ecore_main_loop_quit();
}
static void add_signal_handler(void)
@@ -174,6 +170,13 @@ static void add_signal_handler(void)
signal(SIGINT, sig_term_handler);
}
+static Eina_Bool quit_main_loop(void *user_data)
+{
+ _D("Quit main loop");
+ ecore_main_loop_quit();
+ return ECORE_CALLBACK_CANCEL;
+}
+
int resourced_init(struct daemon_arg *darg)
{
int ret_code;
@@ -190,6 +193,11 @@ int resourced_init(struct daemon_arg *darg)
_D("argment swaptype = %s", swap_arg[opts.enable_swap]);
add_signal_handler();
edbus_init();
+ /* we couldn't create timer in signal callback, due ecore_timer_add
+ * alocates memory */
+ darg->ecore_quit = ecore_timer_add(TIME_TO_SAFE_DATA, quit_main_loop, NULL);
+ ecore_timer_freeze(darg->ecore_quit);
+
return RESOURCED_ERROR_NONE;
}
diff --git a/src/resourced/init.h b/src/resourced/init.h
index 000406cf..ec6e0614 100644
--- a/src/resourced/init.h
+++ b/src/resourced/init.h
@@ -27,6 +27,8 @@
#ifndef _RESOURCED_INIT_H
#define _RESOURCED_INIT_H
+#include <Ecore.h>
+
#include "resourced.h"
#include "daemon-options.h"
@@ -36,6 +38,7 @@ struct daemon_arg {
int argc;
char **argv;
struct daemon_opts *opts;
+ Ecore_Timer *ecore_quit;
};
int resourced_init(struct daemon_arg *darg);
diff --git a/src/swap/swap.c b/src/swap/swap.c
index 740bed61..06a7caf8 100644
--- a/src/swap/swap.c
+++ b/src/swap/swap.c
@@ -29,6 +29,8 @@
#include "swap-common.h"
#include "notifier.h"
#include "proc-process.h"
+#include "proc-main.h"
+#include "config-parser.h"
#include <resourced.h>
#include <trace.h>
@@ -46,10 +48,14 @@
#define MAX_SWAP_VICTIMS 16
#define MEMCG_PATH "/sys/fs/cgroup/memory"
+
+#define BACKCG_PATH MEMCG_PATH"/background"
+#define BACKCG_PROCS BACKCG_PATH"/cgroup.procs"
+
#define SWAPCG_PATH MEMCG_PATH"/swap"
#define SWAPCG_PROCS SWAPCG_PATH"/cgroup.procs"
#define SWAPCG_USAGE SWAPCG_PATH"/memory.usage_in_bytes"
-#define SWAPCG_RECLAIM SWAPCG_PATH"/memory.force_reclaim"
+#define SWAPCG_LIMIT SWAPCG_PATH"/memory.limit_in_bytes"
#define SWAP_ON_EXEC_PATH "/sbin/swapon"
#define SWAP_OFF_EXEC_PATH "/sbin/swapoff"
@@ -59,6 +65,11 @@
#define SWAPFILE_NAME "/dev/zram0"
+#define SWAP_CONF_FILE "/etc/resourced/swap.conf"
+#define SWAP_CONTROL "SWAP_CONTROL"
+#define SWAP_HARD_LIMIT "SWAP_HARD_LIMIT"
+#define SWAP_HARD_LIMIT_DEFAULT 0.5
+
#define SWAP_PATH_MAX 100
#define MBtoB(x) (x<<20)
@@ -70,14 +81,19 @@
#define SWAP_TIMER_INTERVAL 0.5
#define SWAP_PRIORITY 20
-#define SWAP_COUNT_MAX 5
+#define SWAP_SORT_MAX 10
+#define SWAP_COUNT_MAX 5
-struct swap_data_type {
- enum swap_status_type status_type;
- unsigned long *args;
+struct task_info {
+ pid_t pid;
+ pid_t pgid;
+ int oom_score_adj;
+ int size;
+ int cgroup_cnt;
};
static int swapon;
+static float hard_limit_fraction = SWAP_HARD_LIMIT_DEFAULT;
static pthread_mutex_t swap_mutex;
static pthread_cond_t swap_cond;
static Ecore_Timer *swap_timer = NULL;
@@ -85,37 +101,6 @@ static Ecore_Timer *swap_timer = NULL;
static const struct module_ops swap_modules_ops;
static const struct module_ops *swap_ops;
-pid_t swap_victims[MAX_SWAP_VICTIMS];
-
-static int swap_set_candidate_pid(void *data)
-{
- unsigned long *args = data;
- int i;
- int *pid_array = (int*)args[0];
- int count = (int)args[1];
-
- memset(swap_victims, 0, sizeof(int)*MAX_SWAP_VICTIMS);
-
- for (i = 0; i < count; i++)
- swap_victims[i] = pid_array[i];
-
- return RESOURCED_ERROR_NONE;
-}
-
-static pid_t swap_get_candidate_pid(void)
-{
- int i;
- pid_t pid = 0;
-
- for (i = 0; i < MAX_SWAP_VICTIMS; i++)
- if(swap_victims[i]) {
- pid = swap_victims[i];
- swap_victims[i] = 0;
- break;
- }
- return pid;
-}
-
static int swap_get_swap_type(void)
{
struct shared_modules_data *modules_data = get_shared_modules_data();
@@ -134,88 +119,270 @@ static void swap_set_swap_type(int type)
modules_data->swap_data.swaptype = type;
}
-static int swap_check_swap_pid(int pid)
+static unsigned long swap_calculate_hard_limit(unsigned long swap_cg_usage)
{
- char buf[SWAP_PATH_MAX] = {0,};
- int swappid;
- int ret = 0;
- FILE *f;
+ return (unsigned long)(swap_cg_usage * hard_limit_fraction);
+}
- f = fopen(SWAPCG_PROCS, "r");
- if (!f) {
- _E("%s open failed", SWAPCG_PROCS);
- return RESOURCED_ERROR_FAIL;
+static int load_swap_config(struct parse_result *result, void *user_data)
+{
+ int limit_value;
+
+ if (!result) {
+ _E("Invalid parameter: result is NULL");
+ return -EINVAL;
}
- while (fgets(buf, SWAP_PATH_MAX, f) != NULL) {
- swappid = atoi(buf);
- if (swappid == pid) {
- ret = swappid;
- break;
+ if (!strncmp(result->section, SWAP_CONTROL, strlen(SWAP_CONTROL))) {
+ if (!strncmp(result->name, SWAP_HARD_LIMIT, strlen(SWAP_CONTROL))) {
+ limit_value = (int)strtoul(result->value, NULL, 0);
+ if (limit_value < 0 || limit_value > 100) {
+ _E("Invalid %s value in %s file, setting %f as default percent value",
+ SWAP_HARD_LIMIT, SWAP_CONF_FILE, SWAP_HARD_LIMIT_DEFAULT);
+ return RESOURCED_ERROR_NONE;
+ }
+
+ hard_limit_fraction = (float)limit_value/100;
}
}
- fclose(f);
- return ret;
+ _D("hard limit fraction for swap module is %f", hard_limit_fraction);
+ return RESOURCED_ERROR_NONE;
}
-static int swap_check_swap_cgroup(void)
+static int swap_move_to_swap_cgroup(pid_t pid)
{
- char buf[SWAP_PATH_MAX] = {0,};
- int ret = SWAP_FALSE;
+ int size;
FILE *f;
+ char buf[SWAP_PATH_MAX] = {0,};
- f = fopen(SWAPCG_PROCS, "r");
+ f = fopen(SWAPCG_PROCS, "w");
if (!f) {
- _E("%s open failed", SWAPCG_PROCS);
+ _E("Fail to %s file open", SWAPCG_PROCS);
return RESOURCED_ERROR_FAIL;
}
- while (fgets(buf, SWAP_PATH_MAX, f) != NULL) {
- ret = SWAP_TRUE;
- break;
- }
+
+ _D("Moving task %d to swap cgroup", pid);
+ size = sprintf(buf, "%d", pid);
+ if (fwrite(buf, size, 1, f) != 1)
+ _E("fwrite cgroup tasks to swap cgroup failed : %d\n", pid);
fclose(f);
- return ret;
+
+ return RESOURCED_ERROR_NONE;
}
-static int swap_thread_do(FILE *procs, FILE *usage_in_bytes, FILE *force_reclaim)
+/*
+ * check current mem usage total, and caculate to move swap cgroup
+ */
+static int swap_victims(GArray *victim_candidates)
{
- char buf[SWAP_PATH_MAX] = {0,};
- char appname[SWAP_PATH_MAX];
- pid_t pid = 0;
- int size;
- int swap_cg_cnt=0;
- unsigned long usage, nr_to_reclaim;
+ int i, ret, loop_max;
+ int total_usage = 0;
+ int swap_size = 0;
+ struct sysinfo si;
+ char appname[PROC_NAME_MAX];
+
+ if (!sysinfo(&si))
+ total_usage = si.totalram - si.freeram;
+
+ if (!total_usage) {
+ _E("sysinfo failed");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ swap_size = total_usage >> 3;
- /* check swap cgroup count */
- while (fgets(buf, SWAP_PATH_MAX, procs) != NULL) {
+ if (victim_candidates->len < SWAP_COUNT_MAX)
+ loop_max = victim_candidates->len;
+ else
+ loop_max = SWAP_COUNT_MAX;
+
+ _D("Received %d victims to be moved to swap cgroup. Moving %d tasks", victim_candidates->len, loop_max);
+ for (i=0; i<loop_max; i++) {
+ struct task_info tsk;
+
+ tsk = g_array_index(victim_candidates, struct task_info, i);
+
+ if (i == 0) {
+ ret = proc_get_cmdline(tsk.pid, appname);
+ if (ret == RESOURCED_ERROR_FAIL)
+ continue;
+ /* To DO : kill highest 1 process */
+ kill(tsk.pid, SIGKILL);
+ _E("we killed %d (%s)", tsk.pid, appname);
+ }
+
+ swap_move_to_swap_cgroup(tsk.pid);
+ swap_size -= tsk.size;
+
+ if (swap_size < 0)
+ return RESOURCED_ERROR_NONE;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
+/*
+ * sorting by mem usage and LRU
+ */
+static int swap_sort_LRU(const struct task_info *ta, const struct task_info *tb)
+{
+ /* sort by LRU */
+ assert(ta != NULL);
+ assert(tb != NULL);
+
+ return ((int)(tb->cgroup_cnt) - (int)(ta->cgroup_cnt));
+}
+
+static int swap_sort_usage(const struct task_info *ta, const struct task_info *tb)
+{
+ /*
+ * sort by task size
+ */
+ assert(ta != NULL);
+ assert(tb != NULL);
+
+ return ((int)(tb->size) - (int)(ta->size));
+}
+
+static bool get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
+{
+ FILE *fp;
+ char proc_path[SWAP_PATH_MAX];
+
+ sprintf(proc_path, "/proc/%d/statm", pid);
+ fp = fopen(proc_path, "r");
+ if (fp == NULL)
+ return false;
+
+ if (fscanf(fp, "%*s %d", rss) < 1) {
+ fclose(fp);
+ return false;
+ }
+
+ fclose(fp);
+
+ /* convert page to Kb */
+ *rss *= 4;
+ return true;
+}
+
+
+/*
+ * check background mem usage.
+ */
+static int swap_check_cgroup_victims(void)
+{
+ FILE *f = NULL;
+ int i = 0;
+ int cnt = 0;
+ int ret;
+ char buf[SWAP_PATH_MAX] = {0, };
+ GArray *victim_candidates = NULL;
+
+ victim_candidates = g_array_new(false, false, sizeof(struct task_info));
+
+ /* if g_array_new fails, return the current number of victims */
+ if (victim_candidates == NULL) {
+ _E("victim_candidates failed");
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (f == NULL) {
+ f = fopen(BACKCG_PROCS, "r");
+ if (f == NULL) {
+ _E("%s open failed", BACKCG_PROCS);
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ while (fgets(buf, 32, f) != NULL) {
+ struct task_info new_victim;
pid_t tpid = 0;
int toom = 0;
- int ret;
+ unsigned int tsize = 0;
- if (!pid) {
- tpid = atoi(buf);
+ tpid = atoi(buf);
- if (proc_get_oom_score_adj(tpid, &toom) < 0) {
- _D("pid(%d) was already terminated", tpid);
- continue;
- }
+ if (proc_get_oom_score_adj(tpid, &toom) < 0) {
+ _D("pid(%d) was already terminated", tpid);
+ continue;
+ }
- if (toom < OOMADJ_BACKGRD_UNLOCKED)
- continue;
+ if (!get_mem_usage_by_pid(tpid, &tsize)) {
+ _D("pid(%d) size is not available\n", tpid);
+ continue;
+ }
- ret = proc_get_cmdline(tpid, appname);
- if (ret == RESOURCED_ERROR_FAIL)
- continue;
+ for (i = 0; i < victim_candidates->len; i++) {
+ struct task_info *tsk = &g_array_index(victim_candidates,
+ struct task_info, i);
+ if (getpgid(tpid) == tsk->pgid) {
+ tsk->size += tsize;
+ if (tsk->oom_score_adj <= 0 && toom > 0) {
+ tsk->pid = tpid;
+ tsk->oom_score_adj = toom;
+ tsk->cgroup_cnt = cnt;
+ }
+ break;
+ }
+ }
- pid = tpid;
+ if (i == victim_candidates->len) {
+ new_victim.pid = tpid;
+ new_victim.pgid = getpgid(tpid);
+ new_victim.oom_score_adj = toom;
+ new_victim.size = tsize;
+ new_victim.cgroup_cnt = cnt;
+
+ g_array_append_val(victim_candidates, new_victim);
}
- swap_cg_cnt++;
+
+ cnt++;
}
- /* swap cgroup count is MAX, kill 1 process */
- if (swap_cg_cnt >= SWAP_COUNT_MAX) {
- kill(pid, SIGKILL);
- _E("we killed %d (%s)", pid, appname);
+ if (victim_candidates->len == 0) {
+ _E("victim_candidates->len = %d", victim_candidates->len);
+ g_array_free(victim_candidates, true);
+ fclose(f);
+ return RESOURCED_ERROR_NO_DATA;
+ }
+
+ /* sort by mem usage */
+ g_array_sort(victim_candidates, (GCompareFunc)swap_sort_usage);
+
+ if (victim_candidates->len > SWAP_SORT_MAX)
+ g_array_remove_range(victim_candidates, SWAP_SORT_MAX, victim_candidates->len - SWAP_SORT_MAX);
+
+ /* sort by LRU */
+ g_array_sort(victim_candidates, (GCompareFunc)swap_sort_LRU);
+
+ ret = swap_victims(victim_candidates);
+ if (ret) {
+ _E("swap_victims error");
+ g_array_free(victim_candidates, true);
+ fclose(f);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ g_array_free(victim_candidates, true);
+
+ fclose(f);
+ return RESOURCED_ERROR_NONE;
+}
+
+static int swap_thread_do(FILE *procs, FILE *usage_in_bytes, FILE *limit_in_bytes)
+{
+ char buf[SWAP_PATH_MAX] = {0,};
+ int size;
+ int ret;
+ unsigned long usage;
+ unsigned long swap_cg_limit;
+
+ ret = swap_check_cgroup_victims();
+
+ if (ret < 0) {
+ _E("swap_check_cgroup_victims error");
+ return RESOURCED_ERROR_FAIL;
}
/* cacluate reclaim size by usage and swap cgroup count */
@@ -224,11 +391,13 @@ static int swap_thread_do(FILE *procs, FILE *usage_in_bytes, FILE *force_reclaim
usage = (unsigned long)atol(buf);
- nr_to_reclaim = BtoPAGE(usage) >> ((swap_cg_cnt >> 1) + 1);
+ swap_cg_limit = swap_calculate_hard_limit(usage);
+ _D("swap cgroup usage is %lu, hard limit set to %lu (hard limit fraction %f)",
+ usage, swap_cg_limit, hard_limit_fraction);
/* set reclaim size */
- size = sprintf(buf, "%lu", nr_to_reclaim);
- if (fwrite(buf, 1, size, force_reclaim) != size)
+ size = sprintf(buf, "%lu", swap_cg_limit);
+ if (fwrite(buf, 1, size, limit_in_bytes) != size)
_E("fwrite %s\n", buf);
return RESOURCED_ERROR_NONE;
@@ -236,37 +405,31 @@ static int swap_thread_do(FILE *procs, FILE *usage_in_bytes, FILE *force_reclaim
static void *swap_thread_main(void * data)
{
- FILE *procs = NULL;
- FILE *usage_in_bytes = NULL;
- FILE *force_reclaim = NULL;
+ FILE *procs;
+ FILE *usage_in_bytes;
+ FILE *limit_in_bytes;
setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY);
+ procs = fopen(SWAPCG_PROCS, "r");
if (procs == NULL) {
- procs = fopen(SWAPCG_PROCS, "r");
- if (procs == NULL) {
- _E("%s open failed", SWAPCG_PROCS);
- return NULL;
- }
+ _E("%s open failed", SWAPCG_PROCS);
+ return NULL;
}
+ usage_in_bytes = fopen(SWAPCG_USAGE, "r");
if (usage_in_bytes == NULL) {
- usage_in_bytes = fopen(SWAPCG_USAGE, "r");
- if (usage_in_bytes == NULL) {
- _E("%s open failed", SWAPCG_USAGE);
- fclose(procs);
- return NULL;
- }
+ _E("%s open failed", SWAPCG_USAGE);
+ fclose(procs);
+ return NULL;
}
- if (force_reclaim == NULL) {
- force_reclaim = fopen(SWAPCG_RECLAIM, "w");
- if (force_reclaim == NULL) {
- _E("%s open failed", SWAPCG_RECLAIM);
- fclose(procs);
- fclose(usage_in_bytes);
- return NULL;
- }
+ limit_in_bytes = fopen(SWAPCG_LIMIT, "w");
+ if (limit_in_bytes == NULL) {
+ _E("%s open failed", SWAPCG_LIMIT);
+ fclose(procs);
+ fclose(usage_in_bytes);
+ return NULL;
}
while (1) {
@@ -281,10 +444,10 @@ static void *swap_thread_main(void * data)
fseek(procs, 0, SEEK_SET);
fseek(usage_in_bytes, 0, SEEK_SET);
- fseek(force_reclaim, 0, SEEK_SET);
+ fseek(limit_in_bytes, 0, SEEK_SET);
_D("swap_thread_do start");
- swap_thread_do(procs, usage_in_bytes, force_reclaim);
+ swap_thread_do(procs, usage_in_bytes, limit_in_bytes);
_D("swap_thread_do end");
pthread_mutex_unlock(&swap_mutex);
}
@@ -293,18 +456,45 @@ static void *swap_thread_main(void * data)
fclose(procs);
if (usage_in_bytes)
fclose(usage_in_bytes);
- if (force_reclaim)
- fclose(force_reclaim);
+ if (limit_in_bytes)
+ fclose(limit_in_bytes);
return NULL;
}
+static pid_t swap_on(void)
+{
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ execl(SWAP_ON_EXEC_PATH, SWAP_ON_EXEC_PATH, "-d", SWAPFILE_NAME, (char *)NULL);
+ exit(0);
+ }
+ swapon = 1;
+ return pid;
+}
+
+static pid_t swap_off(void)
+{
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ execl(SWAP_OFF_EXEC_PATH, SWAP_OFF_EXEC_PATH, SWAPFILE_NAME, (char *)NULL);
+ exit(0);
+ }
+ swapon = 0;
+ return pid;
+}
+
static Eina_Bool swap_send_signal(void *data)
{
int ret;
_D("swap timer callback function start");
+ if(!swapon)
+ swap_on();
+
/* signal to swap_start to start swap */
ret = pthread_mutex_trylock(&swap_mutex);
@@ -354,82 +544,28 @@ static int swap_thread_create(void)
return ret;
}
-static int get_swap_status(void)
-{
- return swapon;
-}
-
-static pid_t swap_on(void)
-{
- pid_t pid = fork();
-
- if (pid == 0) {
- execl(SWAP_ON_EXEC_PATH, SWAP_ON_EXEC_PATH, "-d", SWAPFILE_NAME, (char *)NULL);
- exit(0);
- }
- swapon = 1;
- return pid;
-}
-
-static pid_t swap_off(void)
+int swap_check_swap_pid(int pid)
{
- pid_t pid = fork();
-
- if (pid == 0) {
- execl(SWAP_OFF_EXEC_PATH, SWAP_OFF_EXEC_PATH, SWAPFILE_NAME, (char *)NULL);
- exit(0);
- }
- swapon = 0;
- return pid;
-}
-
-static int restart_swap(void *data)
-{
- int status;
- pid_t pid;
- pid_t ret;
-
- if (!swapon) {
- swap_on();
- return RESOURCED_ERROR_NONE;
- }
-
- pid = fork();
- if (pid == -1) {
- _E("fork() error");
- return RESOURCED_ERROR_FAIL;
- } else if (pid == 0) {
- pid = swap_off();
- ret = waitpid(pid, &status, 0);
- if (ret == -1) {
- _E("Error waiting for swap_off child process (PID: %d, status: %d)", (int)pid, status);
- }
- swap_on();
- exit(0);
- }
- swapon = 1;
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int swap_move_swap_cgroup(void *data)
-{
- int *args = data;
- int size;
- FILE *f;
char buf[SWAP_PATH_MAX] = {0,};
+ int swappid;
+ int ret = 0;
+ FILE *f;
- f = fopen(SWAPCG_PROCS, "w");
+ f = fopen(SWAPCG_PROCS, "r");
if (!f) {
- _E("Fail to %s file open", SWAPCG_PROCS);
+ _E("%s open failed", SWAPCG_PROCS);
return RESOURCED_ERROR_FAIL;
}
- size = sprintf(buf, "%d", *args);
- if (fwrite(buf, size, 1, f) != 1)
- _E("fwrite cgroup tasks to swap cgroup failed : %d\n", *args);
- fclose(f);
- return RESOURCED_ERROR_NONE;
+ while (fgets(buf, SWAP_PATH_MAX, f) != NULL) {
+ swappid = atoi(buf);
+ if (swappid == pid) {
+ ret = swappid;
+ break;
+ }
+ }
+ fclose(f);
+ return ret;
}
static void swap_start_pid_edbus_signal_handler(void *data, DBusMessage *msg)
@@ -452,10 +588,8 @@ static void swap_start_pid_edbus_signal_handler(void *data, DBusMessage *msg)
}
_I("swap cgroup entered : pid : %d", (int)pid);
- swap_move_swap_cgroup(&pid);
+ swap_move_to_swap_cgroup(pid);
- if (get_swap_status() == SWAP_OFF)
- restart_swap(NULL);
swap_start(NULL);
}
@@ -486,7 +620,8 @@ static void swap_type_edbus_signal_handler(void *data, DBusMessage *msg)
break;
case 1:
if (swap_get_swap_type() != SWAP_ON) {
- restart_swap(NULL);
+ if (!swapon)
+ swap_on();
swap_set_swap_type(type);
}
break;
@@ -522,10 +657,10 @@ static void swap_dbus_init(void)
register_edbus_signal_handler(RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
SIGNAL_NAME_SWAP_TYPE,
- (void *)swap_type_edbus_signal_handler);
+ (void *)swap_type_edbus_signal_handler, NULL);
register_edbus_signal_handler(RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
SIGNAL_NAME_SWAP_START_PID,
- (void *)swap_start_pid_edbus_signal_handler);
+ (void *)swap_start_pid_edbus_signal_handler, NULL);
ret = edbus_add_methods(RESOURCED_PATH_SWAP, edbus_methods,
ARRAY_SIZE(edbus_methods));
@@ -554,9 +689,9 @@ static int swap_init(void)
static int swap_check_node(void)
{
- FILE *procs = NULL;
- FILE *usage_in_bytes = NULL;
- FILE *force_reclaim = NULL;
+ FILE *procs;
+ FILE *usage_in_bytes;
+ FILE *limit_in_bytes;
procs = fopen(SWAPCG_PROCS, "r");
if (procs == NULL) {
@@ -574,13 +709,13 @@ static int swap_check_node(void)
fclose(usage_in_bytes);
- force_reclaim = fopen(SWAPCG_RECLAIM, "w");
- if (force_reclaim == NULL) {
- _E("%s open failed", SWAPCG_RECLAIM);
+ limit_in_bytes = fopen(SWAPCG_LIMIT, "w");
+ if (limit_in_bytes == NULL) {
+ _E("%s open failed", SWAPCG_LIMIT);
return RESOURCED_ERROR_NO_DATA;
}
- fclose(force_reclaim);
+ fclose(limit_in_bytes);
return RESOURCED_ERROR_NONE;
}
@@ -590,82 +725,40 @@ static int resourced_swap_check_runtime_support(void *data)
return swap_check_node();
}
-static int resourced_swap_status(void *data)
-{
- int ret = RESOURCED_ERROR_NONE;
- struct swap_data_type *s_data;
-
- s_data = (struct swap_data_type *)data;
- switch(s_data->status_type) {
- case SWAP_GET_TYPE:
- ret = swap_get_swap_type();
- break;
- case SWAP_GET_CANDIDATE_PID:
- ret = swap_get_candidate_pid();
- break;
- case SWAP_GET_STATUS:
- ret = get_swap_status();
- break;
- case SWAP_CHECK_PID:
- if (s_data->args)
- ret = swap_check_swap_pid((int)s_data->args[0]);
- else
- ret = RESOURCED_ERROR_FAIL;
- break;
- case SWAP_CHECK_CGROUP:
- ret = swap_check_swap_cgroup();
- break;
- }
- return ret;
-}
-
static int resourced_swap_init(void *data)
{
struct modules_arg *marg = (struct modules_arg *)data;
struct daemon_opts *dopt = marg->opts;
+ int ret;
+
+ ret = config_parse(SWAP_CONF_FILE, load_swap_config, NULL);
+
+ if (ret < 0)
+ return ret;
swap_ops = &swap_modules_ops;
if (dopt->enable_swap)
swap_set_swap_type(dopt->enable_swap);
- register_notifier(RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID, swap_set_candidate_pid);
register_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start);
- register_notifier(RESOURCED_NOTIFIER_SWAP_RESTART, restart_swap);
- register_notifier(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, swap_move_swap_cgroup);
return swap_init();
}
static int resourced_swap_finalize(void *data)
{
- unregister_notifier(RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID, swap_set_candidate_pid);
unregister_notifier(RESOURCED_NOTIFIER_SWAP_START, swap_start);
- unregister_notifier(RESOURCED_NOTIFIER_SWAP_RESTART, restart_swap);
- unregister_notifier(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, swap_move_swap_cgroup);
return RESOURCED_ERROR_NONE;
}
-int swap_status(enum swap_status_type type, unsigned long *args)
-{
- struct swap_data_type s_data;
-
- if (!swap_ops)
- return RESOURCED_ERROR_NONE;
-
- s_data.status_type = type;
- s_data.args = args;
- return swap_ops->status(&s_data);
-}
-
static const struct module_ops swap_modules_ops = {
.priority = MODULE_PRIORITY_NORMAL,
.name = "swap",
.init = resourced_swap_init,
.exit = resourced_swap_finalize,
.check_runtime_support = resourced_swap_check_runtime_support,
- .status = resourced_swap_status,
};
MODULE_REGISTER(&swap_modules_ops)
diff --git a/src/swap/swap.conf b/src/swap/swap.conf
new file mode 100644
index 00000000..74acdb86
--- /dev/null
+++ b/src/swap/swap.conf
@@ -0,0 +1,5 @@
+#Swap module config file
+[SWAP_CONTROL]
+#Swap metrics control
+#SWAP_HARD_LIMIT is the hard limit percent value (should be an integer). Default is 50 (50%).
+SWAP_HARD_LIMIT=50
diff --git a/src/utils/datausage-tool.c b/src/utils/datausage-tool.c
index 24196773..3af105d5 100644
--- a/src/utils/datausage-tool.c
+++ b/src/utils/datausage-tool.c
@@ -29,8 +29,8 @@
#include <string.h>
#include "data_usage.h"
+#include "macro.h"
#include "resourced.h"
-#include "rd-network.h"
#include "const.h"
#include "iface.h"
#include "config.h"
@@ -59,6 +59,8 @@ struct arg_param {
int64_t send_limit;
resourced_roaming_type roaming_type;
char *app_id;
+ char *imsi;
+ resourced_state_t ground;
};
static resourced_ret_c convert_roaming(const char *str,
@@ -131,12 +133,14 @@ static void print_usage()
puts(" -q [--quota] <appid> ");
puts(" -Q [--remove-quota] <appid> ");
puts(" -s [--rst-state] <pkgid> ");
+ puts(" -I [--imsi] sim id ");
+ puts(" -B [--background] background attribute, used for quota ");
}
static enum run_rsml_cmd parse_cmd(int argc, char **argv,
struct arg_param *param)
{
- const char *optstring = "hvla:e:g:uf:t:i:d::G:R:r:O:q:Q:M:s:";
+ const char *optstring = "hvla:e:g:uf:t:i:d::G:R:r:O:q:Q:M:s:I:B";
const struct option options[] = {
{"help", no_argument, 0, 'h'},
@@ -158,6 +162,8 @@ static enum run_rsml_cmd parse_cmd(int argc, char **argv,
{"remove-quota", required_argument, 0, 'Q'},
{"roaming", required_argument, 0, 'M'},
{"rst-state", required_argument, 0, 's'},
+ {"imsi", required_argument, 0, 'I'},
+ {"background", no_argument, 0, 'B'},
{0, 0, 0, 0}
};
@@ -326,6 +332,16 @@ static enum run_rsml_cmd parse_cmd(int argc, char **argv,
cmd = RESOURCED_RESTRICTION_STATE;
param->app_id = strdup(optarg);
break;
+ case 'I':
+ if (!optarg) {
+ printf("Remove quota option requeres an argument.");
+ exit(EXIT_FAILURE);
+ }
+ param->imsi = strdup(optarg);
+ break;
+ case 'B':
+ param->ground = RESOURCED_STATE_BACKGROUND;
+ break;
default:
printf("Unknown option %c\n", (char)retval);
print_usage();
@@ -342,24 +358,37 @@ static enum run_rsml_cmd parse_cmd(int argc, char **argv,
*/
resourced_cb_ret data_usage_callback(const data_usage_info *info, void *user_data)
{
+ execute_once {
+ printf("%*s|%16s|%16s|%10s|%10s|%10s|%10s|%3s|%3s|%10s|%20s...\n",
+ user_data ? 3 : 20,
+ user_data ? "ift" : "app_id",
+ "from", "to", "fr_rx", "bg_rx",
+ "fr_tx", "bg_tx", "rmg",
+ "hnp", "ifname", "imsi");
+ }
+
/*TODO rewrite this hack*/
if (user_data)
- printf("iftype %d\n", info->iftype);
+ printf("%3d|", info->iftype);
else
- printf("%s\n", info->app_id ? info->app_id : UNKNOWN_APP);
+ printf("%20s|", info->app_id ? info->app_id : UNKNOWN_APP);
if (info->interval) {
- printf("%s\t", ctime(&info->interval->from));
- printf("%s\t", ctime(&info->interval->to));
+ char s[20] = {0};
+ struct tm *l = localtime(&info->interval->from);
+ strftime(s, sizeof(s), "%a, %b %d %Y", l);
+ printf("%17s|", s);
+ l = localtime(&info->interval->to);
+ strftime(s, sizeof(s), "%a, %b %d %Y", l);
+ printf("%17s|", s);
} else
- printf("<entire interval>\t");
+ printf("%35s|", "<entire interval>");
- printf("%ld/%ld\t%ld/%ld/%u/%u/%s\n", info->foreground.cnt.incoming_bytes,
- info->background.cnt.incoming_bytes,
- info->foreground.cnt.outgoing_bytes,
- info->background.cnt.outgoing_bytes,
+ printf("%10ld|%10ld|%3u|%3u|%10s|%20s\n", info->cnt.incoming_bytes,
+ info->cnt.outgoing_bytes,
info->roaming, info->hw_net_protocol_type,
- info->ifname);
+ info->ifname,
+ info->imsi);
return RESOURCED_CONTINUE;
}
@@ -374,10 +403,10 @@ resourced_cb_ret restriction_callback(const resourced_restriction_info *info,
void *user_data)
{
printf("appid: %s, iftype: %d, rst_state %d, rcv_limit %d, "
- "send_limit %d, roaming %d\n",
+ "send_limit %d, roaming %d, quota_id %d\n",
info->app_id ? info->app_id : UNKNOWN_APP,
info->iftype, info->rst_state,
- info->rcv_limit, info->send_limit, info->roaming);
+ info->rcv_limit, info->send_limit, info->roaming, info->quota_id);
return RESOURCED_CONTINUE;
}
@@ -513,20 +542,21 @@ int main(int argc, char **argv)
case RESOURCED_SET_QUOTA:
{
data_usage_quota quota = { 0 };
- if (!param.du_rule.from || !param.du_rule.to) {
- fprintf(stderr, "Quota command requires all of this options: "
- "--from, --to and --roaming\n");
- break;
- }
-
+ time_t quota_start_time = 0;
/* TODO in case of refactoring, use internal command line structure instead of public structure for holding param */
- time_t quota_start_time = time(NULL);
- quota.start_time = &quota_start_time;
+ if (param.du_rule.from)
+ quota.start_time = &param.du_rule.from;
+ else {
+ quota_start_time = time(NULL);
+ quota.start_time = &quota_start_time;
+ }
quota.snd_quota = param.send_limit;
quota.rcv_quota = param.rcv_limit;
quota.iftype = param.du_rule.iftype;
- quota.time_period = param.du_rule.to - param.du_rule.from;
+ quota.time_period = param.du_rule.granularity;
quota.roaming_type = param.roaming_type;
+ quota.imsi = param.imsi;
+ quota.quota_type = param.ground;
if (set_datausage_quota(param.app_id, &quota) !=
RESOURCED_ERROR_NONE) {
fprintf(stderr, "Failed to apply quota!\n");
@@ -540,6 +570,8 @@ int main(int argc, char **argv)
rule.app_id = param.app_id;
rule.iftype = param.du_rule.iftype;
rule.roaming = param.roaming_type;
+ rule.imsi = param.imsi;
+ rule.quota_type = param.ground;
if (remove_datausage_quota(&rule) != RESOURCED_ERROR_NONE) {
fprintf(stderr, "Failed to remove quota!\n");