tizen 2.3 release tizen_2.3 submit/tizen_2.3/20150202.082807 tizen_2.3_release
authorjk7744.park <jk7744.park@samsung.com>
Sun, 1 Feb 2015 05:45:36 +0000 (14:45 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Sun, 1 Feb 2015 05:45:36 +0000 (14:45 +0900)
182 files changed:
CMakeLists.txt
CMakeLists/init-cmake-projects.txt [deleted file]
CMakeLists/init-needed-environment.txt [deleted file]
CMakeLists/libs.txt [deleted file]
CMakeLists/resourced.txt
data/resourced_proc_exclude.ini [new file with mode: 0644]
data/traffic_db.sql [new file with mode: 0644]
docs/description.txt [new file with mode: 0644]
docs/func.txt [new file with mode: 0644]
docs/traffic_db.txt [new file with mode: 0644]
include/data_usage.h [new file with mode: 0755]
include/proc_stat.h
include/rd-network.h [new file with mode: 0755]
include/resourced.h
libresourced.manifest [new file with mode: 0644]
libresourced.pc.in [new file with mode: 0644]
packaging/add_test_net_activity.patch [new file with mode: 0644]
packaging/resourced-cpucgroup.service [new file with mode: 0644]
packaging/resourced-logging.service [new file with mode: 0644]
packaging/resourced-zram.service [new file with mode: 0644]
packaging/resourced.service
packaging/resourced.spec [deleted file]
packaging/resourced_swapoff.service [new file with mode: 0644]
packaging/system-resource.spec [new file with mode: 0644]
powertop-wrapper.manifest [deleted file]
proc-stat.manifest [deleted file]
resourced.conf
resourced.manifest
resourced.rule [new file with mode: 0644]
resourced_nodb.manifest [new file with mode: 0644]
scripts/resourced-cpucgroup.sh [new file with mode: 0644]
scripts/resourced-zram.sh [new file with mode: 0644]
src/common/app-stat.h [new file with mode: 0644]
src/common/appid-helper.c [new file with mode: 0644]
src/common/appid-helper.h [new file with mode: 0644]
src/common/cgroup.c [new file with mode: 0644]
src/common/cgroup.h [new file with mode: 0644]
src/common/config.h.in
src/common/const.h
src/common/daemon-options.h [new file with mode: 0644]
src/common/edbus-handler.c
src/common/edbus-handler.h
src/common/file-helper.c
src/common/file-helper.h
src/common/genl.h [new file with mode: 0644]
src/common/logging-common.h [new file with mode: 0644]
src/common/lowmem-common.h
src/common/macro.h
src/common/module-data.c
src/common/module-data.h
src/common/module.c
src/common/module.h
src/common/notifier.c [new file with mode: 0644]
src/common/notifier.h [new file with mode: 0644]
src/common/swap-common.h [new file with mode: 0644]
src/common/trace.h
src/common/transmission.h [new file with mode: 0644]
src/cpu/cpu.c [new file with mode: 0644]
src/cpu/cpu.conf [new file with mode: 0644]
src/cpu/logging-cpu.c [new file with mode: 0644]
src/logging/include/logging.h [new file with mode: 0644]
src/logging/logging.c [new file with mode: 0644]
src/memory/logging-memory.c [new file with mode: 0644]
src/memory/lowmem-dbus.c
src/memory/lowmem-handler.c
src/memory/lowmem-handler.h
src/memory/lowmem-process.c [deleted file]
src/memory/lowmem-process.h [deleted file]
src/memory/memory.conf [deleted file]
src/memory/memory_eng.conf
src/memory/memory_user.conf
src/memory/stub-memory.c [deleted file]
src/memory/vmpressure-lowmem-handler.c
src/memps/CMakeLists.txt [new file with mode: 0644]
src/memps/memps.c [new file with mode: 0644]
src/network/CMakeLists.txt [new file with mode: 0755]
src/network/app-stat.c [new file with mode: 0644]
src/network/counter-process.c [new file with mode: 0644]
src/network/counter.c [new file with mode: 0644]
src/network/daemon-options.c [new file with mode: 0644]
src/network/datausage-common.c [new file with mode: 0644]
src/network/datausage-quota-processing.c [new file with mode: 0644]
src/network/datausage-quota.c [new file with mode: 0644]
src/network/datausage-vconf-callbacks.c [new file with mode: 0644]
src/network/datausage-vconf-common.c [new file with mode: 0644]
src/network/dummy-tethering.c [new file with mode: 0644]
src/network/dummy_roaming.c [new file with mode: 0644]
src/network/foreach.c [new file with mode: 0644]
src/network/generic-netlink.c [new file with mode: 0644]
src/network/iface-cb.c [new file with mode: 0644]
src/network/iface.c [new file with mode: 0644]
src/network/include/counter-process.h [new file with mode: 0644]
src/network/include/counter.h [new file with mode: 0644]
src/network/include/database.h [new file with mode: 0644]
src/network/include/datausage-common.h [new file with mode: 0644]
src/network/include/datausage-foreach.h [new file with mode: 0644]
src/network/include/datausage-quota-processing.h [new file with mode: 0644]
src/network/include/datausage-quota.h [new file with mode: 0644]
src/network/include/datausage-reset.h [moved from src/common/cpu-common.c with 55% similarity]
src/network/include/datausage-restriction.h [new file with mode: 0644]
src/network/include/datausage-vconf-callbacks.h [new file with mode: 0644]
src/network/include/datausage-vconf-common.h [new file with mode: 0644]
src/network/include/errors.h [new file with mode: 0644]
src/network/include/generic-netlink.h [new file with mode: 0644]
src/network/include/iface-cb.h [moved from src/common/lowmem-common.c with 53% similarity]
src/network/include/iface.h [new file with mode: 0644]
src/network/include/net-cls-cgroup.h [new file with mode: 0644]
src/network/include/netlink-restriction.h [new file with mode: 0644]
src/network/include/nfacct-rule.h [new file with mode: 0644]
src/network/include/nl-helper.h [new file with mode: 0644]
src/network/include/notification.h [new file with mode: 0644]
src/network/include/protocol-info.h [new file with mode: 0644]
src/network/include/restriction-handler.h [new file with mode: 0644]
src/network/include/restriction-helper.h [new file with mode: 0644]
src/network/include/roaming.h [new file with mode: 0644]
src/network/include/settings.h [new file with mode: 0644]
src/network/include/specific-trace.h [new file with mode: 0644]
src/network/include/storage.h [new file with mode: 0644]
src/network/include/tethering-restriction.h [new file with mode: 0644]
src/network/join.c [new file with mode: 0644]
src/network/ktgrabber-restriction.c [new file with mode: 0644]
src/network/main.c [new file with mode: 0644]
src/network/net-activity.c [new file with mode: 0644]
src/network/net-cls-cgroup.c [new file with mode: 0644]
src/network/network-dummy.c [new file with mode: 0644]
src/network/network.c [new file with mode: 0644]
src/network/network.conf [new file with mode: 0644]
src/network/nf-restriction.c [new file with mode: 0644]
src/network/nfacct-rule.c [new file with mode: 0644]
src/network/nl-helper.c [new file with mode: 0644]
src/network/notification.c [new file with mode: 0644]
src/network/options.c [new file with mode: 0644]
src/network/protocol-info.c [new file with mode: 0644]
src/network/reset.c [new file with mode: 0644]
src/network/restriction-handler.c [new file with mode: 0644]
src/network/restriction-helper.c [new file with mode: 0644]
src/network/restriction-local.c [new file with mode: 0644]
src/network/restriction.c [new file with mode: 0644]
src/network/roaming.c [new file with mode: 0644]
src/network/settings.c [new file with mode: 0644]
src/network/specific-trace.c [new file with mode: 0644]
src/network/storage.c [new file with mode: 0644]
src/network/tethering-restriction.c [new file with mode: 0644]
src/network/update.c [new file with mode: 0755]
src/powertop-wrapper/CMakeLists.txt [moved from CMakeLists/powertop-wrapper.txt with 86% similarity]
src/proc-stat/CMakeLists.txt [moved from CMakeLists/proc-stat.txt with 89% similarity]
src/proc-stat/include/proc-main.h
src/proc-stat/include/proc-noti.h
src/proc-stat/include/proc-process.h
src/proc-stat/proc-main.c
src/proc-stat/proc-monitor.c
src/proc-stat/proc-noti.c
src/proc-stat/proc-process.c
src/proc-stat/proc-stat.c
src/proc-stat/proc-winstate.c [deleted file]
src/resourced/init.c
src/resourced/init.h
src/resourced/main.c
src/swap/swap.c [new file with mode: 0644]
src/timer-slack/timer-slack.c [new file with mode: 0644]
src/timer-slack/timer-slack.conf [new file with mode: 0644]
src/timer-slack/timer-slack.h [moved from src/common/cpu-common.h with 65% similarity]
src/utils/cgroup-test.c [new file with mode: 0644]
src/utils/database.c [new file with mode: 0644]
src/utils/datausage-tool.c [new file with mode: 0644]
src/utils/hashtest.c [new file with mode: 0644]
src/utils/iface-test.c [new file with mode: 0644]
src/utils/inodeuser.c [new file with mode: 0644]
src/utils/monitored.c [new file with mode: 0644]
src/utils/portuser.c [new file with mode: 0644]
src/utils/proc-stat-test.c [new file with mode: 0644]
src/utils/test-net-activity.c [new file with mode: 0644]
src/utils/udp-client.c [new file with mode: 0644]
src/utils/udp-common.c [new file with mode: 0644]
src/utils/udp-common.h [new file with mode: 0644]
src/utils/udp-server.c [new file with mode: 0644]
src/vip-agent/vip-process.c [new file with mode: 0644]
src/vip-agent/vip-process.conf [new file with mode: 0644]
src/vip-agent/vip-process.h [moved from src/proc-stat/include/proc-winstate.h with 70% similarity]
src/vip-agent/vip-release-agent.c [new file with mode: 0644]
system-resource.manifest [new file with mode: 0644]
system-resource.pc.in

index 4fef175..543cd8b 100644 (file)
@@ -1,8 +1,118 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
-INCLUDE(${CMAKE_SOURCE_DIR}/CMakeLists/init-needed-environment.txt)
+SET(fw_name "system-resource")
+SET(RESOURCED resourced)
+SET(LIBS libs)
+SET(PROC-STAT proc-stat)
+SET(NETWORK rd-network)
 
-INSTALL(FILES ${CMAKE_SOURCE_DIR}/system-resource.pc DESTINATION lib/pkgconfig)
+IF("${POWERTOP_MODULE}" STREQUAL "ON")
+SET(POWERTOP-WRAPPER powertop-wrapper)
+ENDIF()
+
+PROJECT(${fw_name})
+
+#Set visibility
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -fvisibility=hidden")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -fvisibility=hidden")
+
+#Set as-needed
+SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
+
+#Set debug-mode if needed
+IF("${CMAKE_BUILD_TYPE}" STREQUAL  "DEBUG")
+  STRING(REGEX REPLACE "-O2" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
+  SET(DEBUG_ENABLED 1)
+  SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -O0 -g -pg")
+  SET(CMAKE_VERBOSE_MAKEFILE ON)
+  SET(VERBOSE 1)
+ELSE()
+#set compile size optimization option in case of none DEBUG
+  SET(ADDITIONAL_OFLAGS "-fdata-sections -ffunction-sections -Wl,--gc-sections -fno-exceptions")
+  SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${ADDITIONAL_OFLAGS}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ADDITIONAL_OFLAGS}")
+ENDIF()
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+#following section is needed for pkg-config *.in file
+SET(LIBDIR ${PREFIX}/lib)
+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
+                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()
+
+IF("${POWERTOP_MODULE}" STREQUAL "ON")
+  SET(PC_PROVIDED_LIBS "${PC_PROVIDED_LIBS} -l${POWERTOP-WRAPPER}" )
+ENDIF()
+
+SET(PC_CFLAGS -I\${includedir}/system)
+SET(VERSION ${FULLVER})
+
+CONFIGURE_FILE(
+    lib${RESOURCED}.pc.in
+    ${CMAKE_SOURCE_DIR}/lib${RESOURCED}.pc
+    @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_PUBLIC_DIR          ${CMAKE_SOURCE_DIR}/include)
+SET(RESOURCED_INCLUDEDIR        ${INCLUDE_COMMON_DIR} ${INCLUDE_PUBLIC_DIR})
+
+SET(SOURCE_DIR                  ${CMAKE_SOURCE_DIR}/src)
+SET(UTILS_SOURCE_DIR            ${SOURCE_DIR}/utils)
+SET(RESOURCED_SOURCE_DIR        ${SOURCE_DIR}/resourced)
+SET(PROC-STAT_SOURCE_DIR        ${SOURCE_DIR}/proc-stat)
+IF("${POWERTOP_MODULE}" STREQUAL "ON")
+SET(POWERTOP-WRAPPER_SOURCE_DIR ${SOURCE_DIR}/powertop-wrapper)
+ENDIF()
+SET(MEMORY_SOURCE_DIR           ${SOURCE_DIR}/memory)
+SET(MEMPS_SOURCE_DIR            ${SOURCE_DIR}/memps)
+SET(SWAP_SOURCE_DIR             ${SOURCE_DIR}/swap)
+SET(MODULES_SOURCE_DIR          ${SOURCE_DIR}/modules)
+SET(LOGGING_SOURCE_DIR         ${SOURCE_DIR}/logging)
+SET(NETWORK_SOURCE_DIR          ${SOURCE_DIR}/network)
+SET(COMMON_SOURCE_DIR           ${SOURCE_DIR}/common)
+SET(CPU_SOURCE_DIR              ${SOURCE_DIR}/cpu)
+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/pkgconfig)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig)
 INSTALL(FILES ${CMAKE_SOURCE_DIR}/resourced.conf DESTINATION /etc/dbus-1/system.d)
 
-INCLUDE(${CMAKE_SOURCE_DIR}/CMakeLists/init-cmake-projects.txt)
+FILE(MAKE_DIRECTORY ${RESOURCED}-cmake)
+CONFIGURE_FILE(${CMAKELISTS_DIR}/${RESOURCED}.txt ${RESOURCED}-cmake/CMakeLists.txt COPYONLY)
+
+
+ADD_SUBDIRECTORY(${PROC-STAT_SOURCE_DIR})
+ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/${RESOURCED}-cmake)
+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/init-cmake-projects.txt b/CMakeLists/init-cmake-projects.txt
deleted file mode 100644 (file)
index f24c832..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-FILE(MAKE_DIRECTORY ${LIBS}-cmake)
-CONFIGURE_FILE(${CMAKELISTS_DIR}/${LIBS}.txt ${LIBS}-cmake/CMakeLists.txt COPYONLY)
-
-FILE(MAKE_DIRECTORY ${RESOURCED}-cmake)
-CONFIGURE_FILE(${CMAKELISTS_DIR}/${RESOURCED}.txt ${RESOURCED}-cmake/CMakeLists.txt COPYONLY)
-
-FILE(MAKE_DIRECTORY ${PROC-STAT}-cmake)
-CONFIGURE_FILE(${CMAKELISTS_DIR}/${PROC-STAT}.txt ${PROC-STAT}-cmake/CMakeLists.txt COPYONLY)
-
-IF("${POWERTOP_MODULE}" STREQUAL "ON")
-FILE(MAKE_DIRECTORY ${POWERTOP-WRAPPER}-cmake)
-CONFIGURE_FILE(${CMAKELISTS_DIR}/${POWERTOP-WRAPPER}.txt ${POWERTOP-WRAPPER}-cmake/CMakeLists.txt COPYONLY)
-ENDIF()
-
-ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/${LIBS}-cmake)
-ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/${PROC-STAT}-cmake)
-ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/${RESOURCED}-cmake)
-
-IF("${POWERTOP_MODULE}" STREQUAL "ON")
-ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/${POWERTOP-WRAPPER}-cmake)
-ENDIF()
diff --git a/CMakeLists/init-needed-environment.txt b/CMakeLists/init-needed-environment.txt
deleted file mode 100644 (file)
index 1841174..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-SET(fw_name "resourced")
-SET(RESOURCED resourced)
-
-SET(LIBS libs)
-SET(PROC-STAT proc-stat)
-SET(POWERTOP-WRAPPER powertop-wrapper)
-PROJECT(${fw_name})
-
-#Set modules, all modules are enabled by default
-IF(NOT DEFINED MEMORY_MODULE)
-  SET(MEMORY_MODULE "ON")
-ENDIF()
-IF(NOT DEFINED POWERTOP_MODULE)
-  SET(POWERTOP_MODULE "OFF")
-ENDIF()
-
-#Set visibility
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -fvisibility=hidden")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -fvisibility=hidden")
-
-#Set as-needed
-SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed")
-SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed")
-
-#Set debug-mode if needed
-IF("${CMAKE_BUILD_TYPE}" STREQUAL  "DEBUG")
-  STRING(REGEX REPLACE "-O2" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
-  SET(DEBUG_ENABLED 1)
-  SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -O0 -g -pg")
-  SET(CMAKE_VERBOSE_MAKEFILE ON)
-  SET(VERBOSE 1)
-ELSE()
-#set compile size optimization option in case of none DEBUG
-  SET(ADDITIONAL_OFLAGS "-fdata-sections -ffunction-sections -Wl,--gc-sections -fno-exceptions")
-  SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${ADDITIONAL_OFLAGS}")
-SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ADDITIONAL_OFLAGS}")
-ENDIF()
-
-SET(PREFIX ${CMAKE_INSTALL_PREFIX})
-
-#following section is needed for pkg-config *.in file
-SET(LIBDIR ${PREFIX}/lib)
-SET(INCLUDEDIR ${PREFIX}/include)
-SET(PC_NAME ${fw_name})
-SET(PC_REQUIRED "glib-2.0
-                vconf
-                vconf-internal-keys
-                sqlite3
-                dlog
-                edbus")
-
-SET(PC_PROVIDED_LIBS "-l${PROC-STAT} -l${RESOURCED}")
-
-SET(PC_CFLAGS -I\${includedir}/system)
-SET(VERSION ${FULLVER})
-
-CONFIGURE_FILE(
-    system-resource.pc.in
-    ${CMAKE_SOURCE_DIR}/system-resource.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_PUBLIC_DIR          ${CMAKE_SOURCE_DIR}/include)
-SET(RESOURCED_INCLUDEDIR        ${INCLUDE_COMMON_DIR} ${INCLUDE_PUBLIC_DIR})
-
-SET(SOURCE_DIR                  ${CMAKE_SOURCE_DIR}/src)
-SET(RESOURCED_SOURCE_DIR        ${SOURCE_DIR}/resourced)
-SET(PROC-STAT_SOURCE_DIR        ${SOURCE_DIR}/proc-stat)
-SET(MEMORY_SOURCE_DIR           ${SOURCE_DIR}/memory)
-SET(MODULES_SOURCE_DIR         ${SOURCE_DIR}/modules)
-SET(CGROUP_SOURCE_DIR           ${SOURCE_DIR}/cgroup)
-SET(COMMON_SOURCE_DIR           ${SOURCE_DIR}/common)
-IF("${POWERTOP_MODULE}" STREQUAL "ON")
-SET(POWERTOP-WRAPPER_SOURCE_DIR           ${SOURCE_DIR}/powertop-wrapper)
-ENDIF()
diff --git a/CMakeLists/libs.txt b/CMakeLists/libs.txt
deleted file mode 100644 (file)
index 171cd2c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
-                   ${RESOURCED_SOURCE_DIR})
-
-INCLUDE(FindPkgConfig)
-
-SET (REQUIRES_LIST
-       dlog
-       vconf
-       edbus
-)
-
-pkg_check_modules(pkgs REQUIRED ${REQUIRES_LIST})
-
-FOREACH(flag ${pkgs_CFLAGS})
-        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC")
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
index 23e21bc..1bcb012 100644 (file)
 CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
 
+#CMake doesnt' support same project name for several TARGETS
+# libresourced uses it
 PROJECT(resource_d)
 
 SET(CMAKE_EXTRA_INCLUDE_FILES unistd.h)
 
 INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
   ${RESOURCED_SOURCE_DIR}
+  ${LOGGING_SOURCE_DIR}/include
   ${MEMORY_SOURCE_DIR}
-  ${PROC-STAT_SOURCE_DIR}/include)
-
-CONFIGURE_FILE(${INCLUDE_COMMON_DIR}/config.h.in
-  ${INCLUDE_COMMON_DIR}/config.h)
+  ${PROC-STAT_SOURCE_DIR}/include
+  ${APP-STAT_SOURCE_DIR}/include
+  ${NETWORK_SOURCE_DIR}/include)
 
 SET (HEADERS
+  ${NETWORK_SOURCE_DIR}/include/datausage-vconf-callbacks.h
+  ${NETWORK_SOURCE_DIR}/include/iface-cb.h
   ${INCLUDE_COMMON_DIR}/config.h
   ${INCLUDE_COMMON_DIR}/config-parser.h
+  ${INCLUDE_COMMON_DIR}/const.h
+  ${INCLUDE_COMMON_DIR}/daemon-options.h
   ${INCLUDE_COMMON_DIR}/macro.h
+  ${INCLUDE_COMMON_DIR}/logging-common.h
   ${INCLUDE_COMMON_DIR}/lowmem-common.h
-  ${INCLUDE_COMMON_DIR}/module.h
-  ${INCLUDE_COMMON_DIR}/const.h
   ${INCLUDE_COMMON_DIR}/module-data.h
-  ${INCLUDE_COMMON_DIR}/cpu-common.h
-  )
+  ${INCLUDE_COMMON_DIR}/module.h
+  ${INCLUDE_COMMON_DIR}/swap-common.h
+)
 
 SET (SOURCES
+  ${COMMON_SOURCE_DIR}/cgroup.c
+  ${COMMON_SOURCE_DIR}/notifier.c
+  ${COMMON_SOURCE_DIR}/appid-helper.c
   ${COMMON_SOURCE_DIR}/config-parser.c
   ${COMMON_SOURCE_DIR}/edbus-handler.c
   ${COMMON_SOURCE_DIR}/file-helper.c
   ${COMMON_SOURCE_DIR}/module-data.c
   ${COMMON_SOURCE_DIR}/module.c
-  ${COMMON_SOURCE_DIR}/lowmem-common.c
-  ${COMMON_SOURCE_DIR}/cpu-common.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-monitor.c
   ${PROC-STAT_SOURCE_DIR}/proc-noti.c
   ${PROC-STAT_SOURCE_DIR}/proc-process.c
-  ${PROC-STAT_SOURCE_DIR}/proc-winstate.c
+  ${PROC-STAT_SOURCE_DIR}/proc-monitor.c
   ${RESOURCED_SOURCE_DIR}/init.c
   ${RESOURCED_SOURCE_DIR}/main.c
   )
 
+INSTALL(FILES ${DATA_DIR}/${EXCLUDE_LIST_FILE_NAME} DESTINATION /usr/etc)
+#network module
+IF("${NETWORK_MODULE}" STREQUAL "ON")
+
+  IF("${DATAUSAGE_TYPE}" STREQUAL "NFACCT")
+    SET(CONFIG_DATAUSAGE_NFACCT 1)
+    SET(SOURCES ${SOURCES}
+      ${NETWORK_SOURCE_DIR}/nfacct-rule.c
+      ${NETWORK_SOURCE_DIR}/nf-restriction.c
+    )
+  ELSE()
+    SET(SOURCES ${SOURCES}
+      ${NETWORK_SOURCE_DIR}/generic-netlink.c
+      ${NETWORK_SOURCE_DIR}/ktgrabber-restriction.c
+    )
+  ENDIF()
+
+  SET(SOURCES ${SOURCES}
+    ${NETWORK_SOURCE_DIR}/counter-process.c
+    ${NETWORK_SOURCE_DIR}/daemon-options.c
+    ${NETWORK_SOURCE_DIR}/datausage-quota-processing.c
+    ${NETWORK_SOURCE_DIR}/datausage-vconf-callbacks.c
+    ${NETWORK_SOURCE_DIR}/datausage-vconf-common.c
+    ${NETWORK_SOURCE_DIR}/specific-trace.c
+    ${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
+    )
+
+   IF ("${TETHERING_FEATURE}" STREQUAL "ON")
+       SET(TETHERING_FEATURE 1)
+   ENDIF()
+
+   INSTALL(FILES ${NETWORK_SOURCE_DIR}/network.conf
+               DESTINATION /etc/resourced)
+
+ENDIF()
+
+IF("${VIP_AGENT}" STREQUAL "ON")
+  SET(SOURCES ${SOURCES}
+     ${VIP_SOURCE_DIR}/vip-process.c
+    )
+ENDIF()
+
+#logging module
+IF("${LOGGING_MODULE}" STREQUAL "ON")
+  SET(SOURCES ${SOURCES}
+    ${LOGGING_SOURCE_DIR}/logging.c
+    )
+  ADD_DEFINITIONS("-DLOGGING_SUPPORT")
+#logging memory
+  IF("${LOGGING_MEMORY}" STREQUAL "ON")
+    SET(SOURCES ${SOURCES}
+      ${MEMORY_SOURCE_DIR}/logging-memory.c
+      )
+  ENDIF()
+#logging cpu
+  IF("${LOGGING_CPU}" STREQUAL "ON")
+    SET(SOURCES ${SOURCES}
+      ${CPU_SOURCE_DIR}/logging-cpu.c
+      )
+  ENDIF()
+ENDIF()
+
 #memory module
 IF("${MEMORY_MODULE}" STREQUAL "ON")
   SET(SOURCES ${SOURCES}
     ${MEMORY_SOURCE_DIR}/lowmem-dbus.c
-    ${MEMORY_SOURCE_DIR}/lowmem-process.c
-    ${MEMORY_SOURCE_DIR}/vmpressure-lowmem-handler.c
+  )
+  IF("${MEMORY_CGROUP}" STREQUAL "ON")
+    SET(SOURCES ${SOURCES}
+      ${MEMORY_SOURCE_DIR}/vmpressure-lowmem-handler.c
+    )
+  ELSE()
+    SET(SOURCES ${SOURCES}
+      ${MEMORY_SOURCE_DIR}/lowmem-handler.c
     )
-ELSEIF("${MEMORY_MODULE}" STREQUAL "OFF")
+  ENDIF()
+  ADD_DEFINITIONS("-DMEMORY_SUPPORT")
+ENDIF()
+
+#swap module
+IF("${SWAP_MODULE}" STREQUAL "ON")
+  SET(SOURCES ${SOURCES}
+    ${SWAP_SOURCE_DIR}/swap.c
+    )
+  ADD_DEFINITIONS("-DSWAP_SUPPORT")
+ENDIF()
+
+IF("${CPU_MODULE}" STREQUAL "ON")
+  SET(SOURCES ${SOURCES}
+    ${CPU_SOURCE_DIR}/cpu.c
+    )
+ENDIF()
+
+IF("${TIMER_SLACK}" STREQUAL "ON")
   SET(SOURCES ${SOURCES}
-    ${MEMORY_SOURCE_DIR}/stub-memory.c
+    ${TIMER_SOURCE_DIR}/timer-slack.c
     )
 ENDIF()
 
@@ -58,15 +158,21 @@ SET (REQUIRES_LIST ${REQUIRES_LIST}
        ecore
        dlog
        glib-2.0
-    sqlite3
+        sqlite3
        vconf
        vconf-internal-keys
-       x11
-       ecore-x
-       ecore-input
        ecore-file
-       evas
-       edbus)
+       eina
+       edbus
+       libsystemd-daemon
+       journal
+)
+
+IF("${LOGGING_MODULE}" STREQUAL "ON")
+  SET (REQUIRES_LIST ${REQUIRES_LIST}
+       libsystemd-journal
+  )
+ENDIF()
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(daemon_pkgs REQUIRED ${REQUIRES_LIST})
@@ -77,13 +183,53 @@ ENDFOREACH(flag)
 
 SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
 
+CONFIGURE_FILE(${INCLUDE_COMMON_DIR}/config.h.in
+  ${INCLUDE_COMMON_DIR}/config.h)
+
+ADD_EXECUTABLE(hashtest ${UTILS_SOURCE_DIR}/hashtest.c)
+TARGET_LINK_LIBRARIES(hashtest ${daemon_pkgs_LDFLAGS})
+
+ADD_EXECUTABLE(cgroup-test ${UTILS_SOURCE_DIR}/cgroup-test.c
+       ${COMMON_SOURCE_DIR}/cgroup.c
+       ${COMMON_SOURCE_DIR}/file-helper.c
+       ${COMMON_SOURCE_DIR}/appid-helper.c
+       ${NETWORK_SOURCE_DIR}/net-cls-cgroup.c
+       )
+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}
+)
+
+IF("${NETWORK_MODULE}" STREQUAL "ON")
+  TARGET_LINK_LIBRARIES(${PROJECT_NAME}
+    resourced
+    app-stat
+    storage
+    settings
+    net-cls
+    roaming
+    net-iface
+  )
+
+  IF("${CMAKE_BUILD_TYPE}" STREQUAL  "DEBUG")
+       ADD_EXECUTABLE(test-udp-server ${UTILS_SOURCE_DIR}/udp-server.c ${UTILS_SOURCE_DIR}/udp-common.c)
+       ADD_EXECUTABLE(test-udp-client ${UTILS_SOURCE_DIR}/udp-client.c ${UTILS_SOURCE_DIR}/udp-common.c)
+  ADD_EXECUTABLE(iface-test ${UTILS_SOURCE_DIR}/iface-test.c)
+  TARGET_LINK_LIBRARIES(iface-test net-iface ${daemon_pkgs_LDFLAGS})
+
+  ENDIF()
+
+  INSTALL(FILES ${DATA_DIR}/traffic_db.sql
+    DESTINATION /usr/share)
+ENDIF()
+
+INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/resourced.h DESTINATION include/system)
 
 SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SKIP_BUILD_RPATH true)
 INSTALL(FILES ${PROJECT_NAME}
-  DESTINATION ${CMAKE_INSTALL_PREFIX}/bin RENAME resourced
+  DESTINATION ${MAKE_INSTALL_PREFIX}/usr/bin RENAME resourced
   PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE WORLD_EXECUTE)
 
 IF("${MEMORY_ENG}" STREQUAL "ON")
@@ -94,7 +240,25 @@ ELSE()
     DESTINATION /etc/resourced RENAME memory.conf)
 ENDIF()
 
-INSTALL(FILES ${MEMORY_SOURCE_DIR}/memory.conf DESTINATION /etc/resourced)
+IF("${SWAP_MODULE}" STREQUAL "ON")
+       INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/scripts/resourced-zram.sh DESTINATION bin)
+ENDIF()
 
-INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/resourced.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/system)
+IF("${CPU_MODULE}" STREQUAL "ON")
+  INSTALL(FILES ${CPU_SOURCE_DIR}/cpu.conf
+    DESTINATION /etc/resourced RENAME cpu.conf)
+ELSE()
+  INSTALL(PROGRAMS ${CMAKE_BINARY_DIR}/scripts/resourced-cpucgroup.sh DESTINATION bin)
+ENDIF()
 
+IF("${TIMER_SLACK}" STREQUAL "ON")
+  INSTALL(FILES ${TIMER_SOURCE_DIR}/timer-slack.conf
+    DESTINATION /etc/resourced RENAME timer-slack.conf)
+ENDIF()
+
+IF("${VIP_AGENT}" STREQUAL "ON")
+ADD_EXECUTABLE(vip-release-agent ${VIP_SOURCE_DIR}/vip-release-agent.c)
+TARGET_LINK_LIBRARIES(vip-release-agent dlog)
+INSTALL(TARGETS vip-release-agent DESTINATION /usr/bin)
+INSTALL(FILES ${VIP_SOURCE_DIR}/vip-process.conf DESTINATION /etc/resourced RENAME vip-process.conf)
+ENDIF()
diff --git a/data/resourced_proc_exclude.ini b/data/resourced_proc_exclude.ini
new file mode 100644 (file)
index 0000000..801f014
--- /dev/null
@@ -0,0 +1,14 @@
+com.samsung.app-tray
+com.samsung.cluster-home
+com.samsung.data-provider-slave
+com.samsung.lockscreen
+com.samsung.pwlock
+com.samsung.admin-data
+com.samsung.quickpanel
+com.samsung.volume
+com.samsung.indicator
+nas9xepmna.context-service
+popup
+testmode
+wakeup-service
+w-home
diff --git a/data/traffic_db.sql b/data/traffic_db.sql
new file mode 100644 (file)
index 0000000..628e669
--- /dev/null
@@ -0,0 +1,66 @@
+PRAGMA journal_mode = PERSIST;
+
+CREATE TABLE IF NOT EXISTS statistics (
+  binpath TEXT,
+  received BIGINT,
+  sent BIGINT,
+  time_stamp BIGINT,
+  iftype INT,
+  is_roaming INT,
+  hw_net_protocol_type INT,
+  ifname TEXT,
+  PRIMARY KEY (binpath, time_stamp, iftype)
+);
+
+CREATE INDEX IF NOT EXISTS binpath_st_idx ON statistics(binpath, iftype);
+
+CREATE TABLE IF NOT EXISTS quotas (
+  binpath TEXT,
+  sent_quota BIGINT,
+  rcv_quota BIGINT,
+  snd_warning_threshold INT,
+  rcv_warning_threshold INT,
+  time_period BIGINT,
+  start_time BIGINT,
+  iftype INT,
+  roaming INT,
+  PRIMARY KEY(binpath, iftype, roaming)
+);
+
+CREATE INDEX IF NOT EXISTS binpath_qt_idx ON quotas(binpath, iftype);
+
+CREATE TABLE IF NOT EXISTS effective_quotas (
+  binpath TEXT,
+  sent_used_quota BIGINT,
+  rcv_used_quota BIGINT,
+  start_time BIGINT,
+  finish_time BIGINT,
+  iftype INT,
+  roaming INT,
+  state INT DEFAULT 0,
+  PRIMARY KEY (binpath, iftype, start_time, finish_time, roaming)
+);
+
+CREATE INDEX IF NOT EXISTS binpath_effective_quotas_idx ON effective_quotas(binpath, iftype);
+
+CREATE TABLE IF NOT EXISTS restrictions (
+  binpath TEXT,
+  rcv_limit BIGINT,
+  send_limit BIGINT,
+  iftype INT,
+  rst_state INT,
+  quota_id INT,
+  roaming INT,
+  PRIMARY KEY (binpath, iftype)
+);
+
+CREATE INDEX IF NOT EXISTS binpath_restrictions_idx ON restrictions(binpath, iftype);
+
+CREATE TABLE IF NOT EXISTS iface_status (
+  update_time BIGINT,
+  iftype INT,
+  ifstatus INT,
+  PRIMARY KEY (update_time)
+);
+
+CREATE INDEX IF NOT EXISTS update_tm_if_idx ON iface_status(update_time, iftype, ifstatus);
diff --git a/docs/description.txt b/docs/description.txt
new file mode 100644 (file)
index 0000000..acecd66
--- /dev/null
@@ -0,0 +1,14 @@
+PCL stands for Performance Control Library.
+
+The libresourced library is designed for accounting and limiting CPU, memory and bandwidth usage of all installed applications and daemons. It provides interface for setting limits and quotas and reading statistics.
+
+- CPU and memory usage are tracked and limited using cpu_acct and mem cgroup controllers
+- Network traffic is controlled by special kernel module which works in conjunction with user-space daemon
+
+Network control is performed on 3rd layer of network subsystem using nethooks. To determine which application sent a packet, the netcls cgroup controller is used which tags all outgoing packets.
+There is no direct way to determine to which application an incoming packet belongs. This is solved by comparing destination host/port pairs of incoming packets to known host/port pairs of sent packets.
+There is also a backup way of determining the packet owner by parsing all the tracked applications' /proc entries.
+
+The daemon periodically collects the data from kernel module and stores it into sqlite database.
+
+Communication between daemon and kernel module is done using netlink interface.
diff --git a/docs/func.txt b/docs/func.txt
new file mode 100644 (file)
index 0000000..b1ce404
--- /dev/null
@@ -0,0 +1,427 @@
+Following is the list of functions that are currently exported in libresourced.so
+
+Types:
+======
+
+/**
+ * @brief Datausage quota
+ */
+typedef struct {
+       int time_period;
+       int64_t snd_quota;
+       int64_t rcv_quota;
+       resman_state_t quota_type;
+} resman_datausage_quota;
+
+/**
+ * @brief return type of the counters callback
+ */
+typedef enum {
+       PCL_CANCEL = 0,                 /**< cancel */
+       PCL_CONTINUE = 1,               /**< continue */
+} resman_cb_ret;
+
+/**
+ * @brief callback for enumerate counters and restrictions
+ */
+typedef resman_cb_ret(*resman_perf_info_cb) (const resman_perf_info * info,
+                                      void *user_data);
+
+/**
+ * @brief Selection rule applied for data usage enumeration
+ */
+typedef struct {
+       time_t from;
+       time_t to;
+       char *iface;
+       int granularity;
+} data_usage_selection_rule;
+
+typedef struct {
+       resman_sql_exec exec;
+} resman_base_query;
+
+typedef resman_ret_c(*resman_sql_exec) (const resman_exec_context *context);
+
+typedef struct {
+       resman_perf_info_cb info_cb;
+       void *user_data;
+       resman_perf_selection_rule *rule;
+} resman_exec_context;
+
+typedef resman_cb_ret(*resman_perf_info_cb) (const resman_perf_info * info,
+                                      void *user_data);
+/**
+ * @brief Bundle structure for bringing all together application identification
+ *     and properties.
+ * 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;
+       const char *iface;
+       resman_tm_interval *interval;
+       resman_common_info foreground;
+       resman_common_info background;
+} resman_perf_info;
+
+/**
+ * @brief Commulative structure for holding data usage information
+ */
+typedef struct {
+       resman_counters cnt;
+       resman_restrictions rst;
+} resman_common_info;
+
+typedef struct {
+       time_t from;
+       time_t to;
+} resman_tm_interval;
+
+resman_ret_c - return value of most functions.
+
+typedef enum {
+       PCL_ERROR_NOTIMPL = -7,
+       PCL_ERROR_UNINITIALIZED = -6,
+       PCL_ERROR_NO_DATA = -5,
+       PCL_ERROR_INVALID_PARAMETER = -4,
+       PCL_ERROR_OUT_OF_MEMORY = -3,
+       PCL_ERROR_DB_FAILED = -2,
+       PCL_ERROR_FAIL = -1,
+       PCL_ERROR_OK = 0
+} resman_ret_c;
+
+/*
+ * cpu_usage: percent of cpu usage
+ * mem_usage: percent of mem usage
+ * incomming_rate_limit: rate limit for incomming packets in bytes per second
+ * outgoing_rate_limit: rate limit for outgoing packets in bytes per second
+ */
+typedef struct {
+       int cpu_usage;
+       int mem_usage;
+       int incoming_rate_limit;
+       int outgoing_rate_limit;
+} resman_restrictions;
+
+/**
+ * @brief Selection rule applied for enumeration
+ * order - order field resman_order_t
+ * filter - fiter field resman_filter
+ * groupping - on what we should groupping our result
+ */
+typedef struct {
+       unsigned char version;
+       u_int32_t order;
+       resman_filter filter;
+       u_int32_t groupping;
+} resman_perf_selection_rule;
+
+Functions:
+==========
+
+int apply_net_restriction(u_int32_t classid, int incoming_rate_limit, int outgoing_rate_limit)
+
+Applies network rate limit to application having the supplied network class ID
+
+classid - network class ID
+incoming_rate_limit - rate limit for incoming traffic
+outgoing_rate_limit - rate limit for outgoing traffic
+
+Return values:
+Non-zero values mean errors while communicating with kernel module
+
+TODO:
+- Currently incoming_rate_limit must be 0, otherwise PCL_ERROR_NOTIMPL will be returned
+
+--------------------------------------------------------------------------------
+resman_ret_c apply_restriction(const char *app_id, const resman_restrictions *foreground, const resman_restrictions *background)
+
+Stores restrictions into database to be applied when application is started again.
+
+app_id - zero-terminated string containing package name of application to be restricted
+foreground - set of restrictions applied to application while in foreground
+background - set of restrictions applied to application while in background
+
+Non-OK return values:
+PCL_ERROR_INVALID_PARAMETER - app_id is NULL
+PCL_ERROR_INVALID_PARAMETER - both foreground and background are NULL
+PCL_ERROR_FAIL - could not determine network class ID for the application
+PCL_ERROR_DB_FAILED - error while storing restrictions to database
+PCL_ERROR_NOTIMPL - incoming_rate_limit is set
+???? - apply_net_restriction can return any non-zero integer value (see above) which will be returned as is
+
+TODO:
+- Does not apply CPU and memory restrictions if application is already running
+- Background settings are ignored
+- Return meaningful result in case apply_net_restriction fails
+
+--------------------------------------------------------------------------------
+resman_ret_c bind_statement(sqlite3_stmt *stm, const resman_perf_selection_rule *rule)
+
+Applies selection rule to the statement.
+
+stm - sqlite statement to bind parameters to
+rule - ???? parameters to be bound to statement
+
+Non-OK return values:
+PCL_ERROR_INVALID_PARAMETER - stm is NULL
+PCL_ERROR_INVALID_PARAMETER - rule filter type is not PCL_FILTER_UNDEF and rule filter value is NULL
+PCL_ERROR_DB_FAILED - database error
+
+TODO:
+The function assumes that bound parameter is always the first parameter to bind. This might break on some statements.
+
+--------------------------------------------------------------------------------
+resman_base_query create_exec(const resman_perf_selection_rule *rule)
+
+Returns a query to be executed based on rule supplied
+
+--------------------------------------------------------------------------------
+int create_netlink(int protocol, int groups)
+
+Create netlink socket.
+
+Results: Created socket on success and -1 on failure.
+
+--------------------------------------------------------------------------------
+resman_ret_c data_usage_details_foreach(const char *app_id,
+                                    data_usage_selection_rule *rule,
+                                    resman_perf_info_cb info_cb, void *user_data)
+
+Process data usage details for application on given interval.
+
+app_id         - null-terminated string containing package name of the application or NULL for all applications
+rule   - parameters of query
+ - from - start of interval
+ - to - end of interval
+ - iface - name of interface or NULL for all interfaces
+ - granularity - split data usage into granularity-sized chunks
+info_cb - pointer to callback to be executed on each record
+user_data - pointer to data which will be passed as argument 3 to callback
+
+Interval is given as a pair of unix timestamps.
+If granularity is not supplied the result is the total data usage on the whole interval. Otherwise there will be one record for each chunk.
+If iface is not supplied there will be one record for each interface.
+If app_id is not supplied then records will contain total amount of data usage by all applications.
+
+info_cb must return PCL_CONTINUE to keep processing results or PCL_CANCEL to stop processing and discard the rest.
+
+Notes:
+Callbacks are issued synchronously. When data_usage_details_foreach returns, all callbacks are guaranteed to have been executed already.
+The function is not thread-safe.
+If granularity is supplied, interval is split into chunks and each record contains traffic during that chunk.
+If interface or granularity is supplied and a record contains no traffic, the record is omitted.
+
+Errors:
+PCL_ERROR_INVALID_PARAMETER    - rule or info_cb is NULL
+PCL_ERROR_DB_FAILED            - database error
+
+--------------------------------------------------------------------------------
+void data_usage_finalize(void)
+
+Finalizes queries used in data usage functions
+
+--------------------------------------------------------------------------------
+resman_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
+                            resman_perf_info_cb info_cb, void *user_data)
+
+Process data usage on given interval.
+
+rule   - parameters of query
+ - from - start of interval
+ - to - end of interval
+ - iface - name of interface or NULL for all interfaces
+ - granularity - split data usage into granularity-sized chunks
+info_cb - pointer to callback to be executed on each record
+user_data - pointer to data which will be passed as argument 3 to callback
+
+Interval is given as a pair of unix timestamps. The result contains records for all applications that used network during that interval.
+If granularity is not supplied each record is the total data usage on the whole interval. Otherwise there is a record for each chunk.
+If iface is supplied the result is limited to that interface. Otherwise the result is a total of all interfaces.
+
+info_cb must return PCL_CONTINUE to keep processing results or PCL_CANCEL to stop processing and discard the rest.
+
+Notes:
+Callbacks are issued synchronously. When data_usage_foreach returns, all callbacks are guaranteed to have been executed already.
+The function is not thread-safe.
+If granularity is supplied, interval is split into chunks and each record contains traffic during that chunk. If any record contains no traffic, the record is omitted.
+
+Errors:
+PCL_ERROR_INVALID_PARAMETER    - rule or info_cb is NULL
+PCL_ERROR_DB_FAILED            - database error
+
+--------------------------------------------------------------------------------
+int data_usage_init(sqlite3 *db)
+
+Initializes queries used in data usage functions.
+
+--------------------------------------------------------------------------------
+void datausage_quota_finalize(void)
+
+Finalizes queries used in data usage quota functions.
+
+--------------------------------------------------------------------------------
+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)
+
+Converts application package name 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
+
+Returns class ID or 0 in case of error.
+
+--------------------------------------------------------------------------------
+sqlite3 *resourced_get_database(void)
+
+Returns the handler to PCL database containing restrictions and statistics.
+
+--------------------------------------------------------------------------------
+int get_family_id(int sock, pid_t pid)
+
+Probe the controller in genetlink to find the family id for the TRAF_STAT family. (Helper function)
+
+--------------------------------------------------------------------------------
+void get_in_info(int sock, const pid_t pid, const int family_id,
+           in_traffic_event_list **list)
+
+Get list of incoming traffic records from the kernel module.
+
+--------------------------------------------------------------------------------
+void get_out_info(int sock, const pid_t pid,
+       const int family_id, out_traffic_event_list **list)
+
+Get list of outgoing traffic records from the kernel module.
+
+--------------------------------------------------------------------------------
+int make_cgroup_with_pid(char *dpg_name, char *app_path)
+
+Creates a cgroup named dkg_name if needed and place current process to that cgroup.
+
+dpkg_name - name of cgroup
+app_path - used only for debugging
+
+Returns 0 on success -errno on error
+
+Notes:
+The name is misleading, PID is not even accepted as a parameter.
+app_path is used only for debugging and not anywhere in the code
+
+--------------------------------------------------------------------------------
+void notify_daemon(void)
+
+Sends SIGUSR1 to the daemon.
+
+--------------------------------------------------------------------------------
+resman_ret_c resman_perf_info_foreach(const resman_perf_selection_rule *rule,
+                               resman_perf_info_cb info_cb, void *user_data)
+
+Processes network usage statistics based on supplied rule.
+
+rule - the rule used for statistics selection
+info_cb - callback performed on each record
+user_data - pointer passed as argument 3 to the callback
+
+Notes:
+Actual behavior depends largely on the rule.
+
+--------------------------------------------------------------------------------
+resman_ret_c resman_sql_rules_exec(const resman_exec_context *context)
+
+Performs the actual query and calls callback on each record.
+
+context - contains the rule and callback
+
+Note:
+Internal function.
+
+--------------------------------------------------------------------------------
+resman_ret_c resman_sql_simple_exec(const resman_exec_context *context)
+
+Performs the basic statistics query and calls callback on each record.
+
+context - contains the rule and callback
+
+Note:
+Internal function.
+
+--------------------------------------------------------------------------------
+void put_attr(rt_param *arg, int type, const void *data, int data_len)
+
+Write attribute to netlink packet. Helper function.
+
+--------------------------------------------------------------------------------
+int receive_answer(int sock, const int attr_type, char **out_buffer, __u16 *arg_count)
+
+Read answer from kernel module. Helper function.
+
+--------------------------------------------------------------------------------
+int revert_net_restriction(u_int32_t classid)
+
+Removes network restrictions set by apply_net_restriction.
+
+classid - network class ID which will be unrestricted
+
+Returns 0 on success, non-zero on failure.
+
+Note:
+Name is a bit misleading in that it removes restrictions, not reverts to previous ones.
+
+--------------------------------------------------------------------------------
+resman_ret_c revert_restriction(const char *app_id)
+
+Removes restrictions set by apply_restriction.
+
+app_id - zero-terminated string containing package name of application.
+
+Returns 0 on success
+PCL_ERROR_DB_FAILED - database error
+???? - any non-zero value could be returned by revert_net_restriction
+
+Notes:
+Does not actually modify CPU or memory limits, only writes new settings to database.
+Name is misleading in that the function removes restrictions, not reverts to previous ones.
+
+--------------------------------------------------------------------------------
+int send_command(int sock, const pid_t pid, const int family_id, __u8 cmd)
+
+Helper function for sending commands to kernel module.
+
+--------------------------------------------------------------------------------
+int send_restriction(int sock, const pid_t pid, const int family_id,
+                const u_int32_t *classids, const u_int16_t classid_count,
+                const enum traffic_restriction_type restriction_type)
+
+Internal function used for setting network restrictions.
+
+--------------------------------------------------------------------------------
+void send_start(int sock, const pid_t pid, const int family_id)
+
+Helper function used in communicating with kernel module.
+
+--------------------------------------------------------------------------------
+resman_ret_c set_datausage_quota(const char *app_id,
+                             const resman_datausage_quota *quota)
+
+Sets network traffic quota for application.
+
+app_id - zero-terminated string containing package name of the application.
+quota - network traffic quota to be applied to the application
+
+Returns:
+PCL_ERROR_OK - success
+PCL_ERROR_INVALID_PARAMETER - app_id or quota is NULL
+
+Note:
+Currently only writes quota limits to the database.
+
diff --git a/docs/traffic_db.txt b/docs/traffic_db.txt
new file mode 100644 (file)
index 0000000..4b5cd0d
--- /dev/null
@@ -0,0 +1,69 @@
+Table of context
+---------------
+
+1. ERD - Entity relation diagram
+2. Statistics entity
+3. Restrictions entity
+4. Quotas entity
+5. Effective quota entity
+
+
+1. ERD
+
+   +----------------------------+     +--------------------+    +-------------+
+   |         restrictions       |     |    statistics      |    |     quotas  |
+   |----------------------------|     |--------------------|    |-------------|
+   |binpath: TEXT               |<--->|binpath: TEXT       |<-->|binpath      |
+   |cpu: INT                    |  |  |received: BIGINT    |    |sent_quota   |
+   |mem: INT                    |  |  |sent: BIGINT        |    |rcv_quota    |
+   |incomming_rate: INT         |  |  |time_stamp: BIGINT  |    |time_period  |
+   |outgoing_rate: INT          |  |  |ifname: TEXT        |    |start_time   |
+   |                            |  |  |ifmac: TEXT         |    +-------------+
+   |                            |  |  |                    |
+   |                            |  |  |                    |
+   +----------------------------+  |  +--------------------+
+                                   |
+                                   |
+                                   |  +---------------------------+
+                                   |  |   effective_quota         |
+                                   |  |---------------------------|
+                                   +->|binpath                    |
+                                      |sent_used_quota            |
+                                      |rcv_used_quota             |
+                                      |start_time                 |
+                                      |finish_time                |
+                                      |                           |
+                                      +---------------------------+
+
+2. Statistics entity
+--------------------
+Holds information about counted traffic per time points, time_stamp - it's time
+point. Accumulation of the information proceses in main loop of perf-controld.
+
+
+3. Restrictions entity
+----------------------
+Holds information about restriction see set_restriction function. Every time we
+set restriction we store it in the database, it give us an ability to apply
+restriction for example after reboot.
+TODO: Possible bug. We don't separate quota based restriction and user based.
+User based restriction should be applied without conditions, quota based should
+be checked is quota active.
+
+
+4. Quotas entity
+----------------
+Holds information about quota.
+
+
+5. Effective quota entity
+-------------------------
+Holds information about active quota. One enty per quotas time interval.
+
+
+     | time period | time period | time period |
+------------------------------------------------------------------------------>
+     ^             ^             ^
+     start time    finish time   finish time
+                   start time    start time
+time line
diff --git a/include/data_usage.h b/include/data_usage.h
new file mode 100755 (executable)
index 0000000..45bc817
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * 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: data_udage.h
+ *
+ *  @desc Data usage API
+ *  @version 1.0
+ *
+ *  Created on: 28 June, 2012
+ */
+
+#ifndef _RESOURCED_DATA_USAGE_H_
+#define _RESOURCED_DATA_USAGE_H_
+
+#include <resourced.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Hardware network protocol types
+ */
+typedef enum {
+       RESOURCED_PROTOCOL_NONE,                        /**< Network unknown */
+       RESOURCED_PROTOCOL_DATACALL_NOSVC,              /**< Network no service */
+       RESOURCED_PROTOCOL_DATACALL_EMERGENCY,          /**< Network emergency */
+       RESOURCED_PROTOCOL_DATACALL_SEARCH,             /**< Network search 1900 */
+       RESOURCED_PROTOCOL_DATACALL_2G,                 /**< Network 2G */
+       RESOURCED_PROTOCOL_DATACALL_2_5G,               /**< Network 2.5G */
+       RESOURCED_PROTOCOL_DATACALL_2_5G_EDGE,          /**< Network EDGE */
+       RESOURCED_PROTOCOL_DATACALL_3G,                 /**< Network UMTS */
+       RESOURCED_PROTOCOL_DATACALL_HSDPA,              /**< Network HSDPA */
+       RESOURCED_PROTOCOL_DATACALL_LTE,                /**< Network LTE */
+       RESOURCED_PROTOCOL_MAX_ELEM
+} resourced_hw_net_protocol_type;
+
+/**
+ * @brief State of the monitored process
+ */
+typedef enum {
+       RESOURCED_STATE_UNKNOWN = 0,
+       RESOURCED_STATE_FOREGROUND = 1 << 1,            /** < foreground state */
+       RESOURCED_STATE_BACKGROUND = 1 << 2,            /** < background state */
+       RESOURCED_STATE_LAST_ELEM = 1 << 3
+} resourced_state_t;
+
+/**
+ * @brief Network restriction states
+ */
+typedef enum {
+       RESOURCED_RESTRICTION_UNKNOWN,
+       RESOURCED_RESTRICTION_ACTIVATED, /** < restriction has been activated */
+       RESOURCED_RESTRICTION_REMOVED,   /** < restriction has been removed */
+       RESOURCED_RESTRICTION_EXCLUDED,  /** < restriction has been excluded */
+       RESOURCED_RESTRICTION_LAST_ELEM
+} resourced_restriction_state;
+
+/**
+ * @brief Network interface types
+ */
+typedef enum {
+       RESOURCED_IFACE_UNKNOWN,        /**< undefined iface */
+       RESOURCED_IFACE_DATACALL,       /**< mobile data */
+       RESOURCED_IFACE_WIFI,           /**< wifi data */
+       RESOURCED_IFACE_WIRED,  /**< wired interface */
+       RESOURCED_IFACE_BLUETOOTH,      /**< bluetooth interface */
+       RESOURCED_IFACE_ALL,    /**< enumerate all network interface types */
+       RESOURCED_IFACE_LAST_ELEM
+} resourced_iface_type;
+
+/**
+ * @brief Network roaming type
+ */
+typedef enum {
+       RESOURCED_ROAMING_UNKNOWN,              /**< can't define roaming - roaming unknown */
+       RESOURCED_ROAMING_ENABLE,               /**< in roaming */
+       RESOURCED_ROAMING_DISABLE,              /**< not in roaming */
+       RESOURCED_ROAMING_LAST_ELEM,
+} resourced_roaming_type;
+
+/*
+ * 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
+ * roaming - roaming support now only for exclusions for restriction it doesn't
+ * make sense (roaming will be saved as UNKNOWN and restriction will be applied
+ * in any case).
+ *
+ */
+typedef struct {
+       resourced_state_t rs_type;
+       resourced_iface_type iftype;
+       int send_limit;
+       int rcv_limit;
+       int snd_warning_limit;
+       int rcv_warning_limit;
+       resourced_roaming_type roaming;
+} resourced_net_restrictions;
+
+/**
+ * @brief the same as for restriction
+ */
+typedef struct {
+       long incoming_bytes;
+       long outgoing_bytes;
+} resourced_counters;
+
+
+/**
+ * @brief Commulative structure for holding data usage information
+ */
+typedef struct {
+       resourced_counters cnt;
+       resourced_net_restrictions rst;
+} resourced_common_info;
+
+typedef struct {
+       time_t from;
+       time_t to;
+} resourced_tm_interval;
+
+typedef enum {
+       RESOURCED_CON_PERIOD_UNKNOWN,                   /**< Undefined period */
+       RESOURCED_CON_PERIOD_LAST_RECEIVED_DATA,        /**< Last received data */
+       RESOURCED_CON_PERIOD_LAST_SENT_DATA,            /**< Last sent data */
+       RESOURCED_CON_PERIOD_TOTAL_RECEIVED_DATA,       /**< Total received data */
+       RESOURCED_CON_PERIOD_TOTAL_SENT_DATA,           /**< Total sent data */
+       RESOURCED_CON_PERIOD_LAST_ELEM
+} resourced_connection_period_type;
+
+/**
+ * @brief Period used in quota
+ */
+typedef enum {
+       RESOURCED_PERIOD_UNDEF = 0,
+       RESOURCED_PERIOD_HOUR = 3600,
+       RESOURCED_PERIOD_DAY = 86400,
+       RESOURCED_PERIOD_WEEK = 604800,
+       RESOURCED_PERIOD_MONTH = 2419200
+} data_usage_quota_period_t;
+
+/**
+ * @brief Restriction notification warning threshold value
+ * definitions
+ */
+enum {
+       WARNING_THRESHOLD_DEFAULT,              /**< for quota it means
+               system-resource will evaluate proper value, for restriction it
+               means no warning */
+       WARNING_THRESHOLD_NONE,                 /**< means no threshold at all */
+};
+
+/**
+ * @brief Datausage quota
+ * time_period - time interval for quota, use predefined quota
+ *  @see data_usage_quota_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 system-resource 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;
+       resourced_state_t quota_type;
+       resourced_iface_type iftype;
+       time_t *start_time;
+       resourced_roaming_type roaming_type;
+} data_usage_quota;
+
+/**
+ * @brief Reset filter for quota
+ * app_id is mandatory field
+ * iftype interface type, RESOURCED_IFACE_UNKNOWN
+ *     interface is not valid parameter, use
+ *     RESOURCED_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.
+ */
+struct datausage_quota_reset_rule {
+       const char *app_id;
+       resourced_iface_type iftype;
+       resourced_roaming_type roaming;
+};
+
+/**
+ * @brief Selection rule applied for data usage enumeration
+ */
+typedef struct {
+       unsigned char version;
+       time_t from;
+       time_t to;
+       resourced_iface_type iftype;
+       int granularity;
+} data_usage_selection_rule;
+
+/**
+ * @brief Bundle structure for bringing all together application identification
+ *     and properties.
+ * 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;
+       const char *ifname;
+       resourced_iface_type iftype;
+       resourced_tm_interval *interval;
+       resourced_common_info foreground;
+       resourced_common_info background;
+       resourced_roaming_type roaming;
+       resourced_hw_net_protocol_type hw_net_protocol_type;
+} data_usage_info;
+
+/**
+ * @brief callback for enumerate counters and restrictions
+ */
+typedef resourced_cb_ret(*data_usage_info_cb) (const data_usage_info *info,
+                                              void *user_data);
+
+
+/**
+ * @desc Description of the boolean option for enabling/disabling
+ *     network interfaces and enabling/disabling some behaviar
+ */
+typedef enum {
+       RESOURCED_OPTION_UNDEF,
+       RESOURCED_OPTION_ENABLE,
+       RESOURCED_OPTION_DISABLE
+} resourced_option_state;
+
+/**
+ * @desc Set of the options.
+ * version - contains structure version
+ * wifi - enable/disable wifi, RESOURCED_OPTION_UNDEF to leave option as is
+ * datacall - enable/disable datacall, RESOURCED_OPTION_UNDEF to leave option as is
+ * datausage_timer - set period of the updating data from the kernel,
+ *     0 to leave option as is
+ * datacall_logging - enable/disable datacall_logging,
+ *     RESOURCED_OPTION_UNDEF to leave option as is
+ */
+typedef struct {
+       unsigned char version;
+       resourced_option_state wifi;
+       resourced_option_state datacall;
+       time_t datausage_timer;
+       resourced_option_state datacall_logging;
+} resourced_options;
+
+/**
+ * @brief Structure for information on restrictions.
+ * 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;
+       resourced_iface_type iftype;
+       resourced_restriction_state rst_state;
+       int rcv_limit;
+       int send_limit;
+       int quota_id;
+       resourced_roaming_type roaming;
+} resourced_restriction_info;
+
+/**
+ * @brief callback for processing information of restrictions
+ */
+typedef resourced_cb_ret(*resourced_restriction_cb)(
+       const resourced_restriction_info *info, void *user_data);
+
+/**
+ * @desc Reset rule. 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
+ *     @see resourced_iface_type, if iftype is RESOURCED_IFACE_LAST_ELEM - erase all
+ *     RESOURCED_IFACE_UNKNOW - means undetermined interface
+ *     on moment of storing data.
+ * interval - It's time interval, @see resourced_tm_interval. 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;
+       resourced_iface_type iftype;
+       resourced_tm_interval *interval;
+       resourced_connection_period_type connection_state;
+} data_usage_reset_rule;
+
+resourced_ret_c reset_data_usage(const data_usage_reset_rule *rule);
+
+struct net_activity_info {
+       int type;               /*<< ingress/egress */
+       char *appid;
+       int iftype;
+       int bytes;
+};
+
+typedef resourced_cb_ret(*net_activity_cb)(struct net_activity_info *info);
+
+
+
+/**
+ * @desc Set and apply restriction for application.
+ *      It will create new restriction or modify existing.
+ * @param app_id[in] - application identifier, it's package name now
+ * @param restriction[in] - restriction to apply for application
+ *     in foreground mode
+ * At least one of the restriction should be setted.
+ * @return 0 on success, otherwise error code
+ */
+resourced_ret_c set_net_restriction(const char *app_id,
+                           const resourced_net_restrictions *restriction);
+
+/**
+ * @desc Remove existing restriction for application
+ *   It will delete restriction rule in kernel
+ * @param app_id[in] - application identifier, it's package name
+ */
+resourced_ret_c remove_restriction(const char *app_id);
+
+resourced_ret_c remove_restriction_by_iftype(const char *app_id,
+                                            const resourced_iface_type iftype);
+
+/**
+ * @desc Exclude restriction for application
+ *   It will exclude restriction rule in kernel
+ * @param app_id[in] - application identifier, it's package name
+ * This function is deprecated, use set_net_exclusion
+ */
+resourced_ret_c exclude_restriction(const char *app_id);
+
+/**
+ * This function is deprecated, use set_net_exclusion
+ */
+resourced_ret_c exclude_restriction_by_iftype(
+       const char *app_id, const resourced_iface_type iftype);
+
+
+/**
+ * @brief Exclude application from network restriction.
+ * Excluded application will be granted to
+ * internet access, in case of whole network restriction.
+ * iftype and roaming in resourced_net_restriction is supported right now
+ */
+resourced_ret_c set_net_exclusion(const char *app_id,
+                       const resourced_net_restrictions *rst);
+
+/**
+ * @desc Remove datausage quota by quota rule
+ */
+resourced_ret_c remove_datausage_quota(
+       const struct datausage_quota_reset_rule *rule);
+
+/**
+ * @deprecated
+ */
+resourced_ret_c remove_datausage_quota_by_iftype(
+       const char *app_id, const resourced_iface_type iftype);
+
+/**
+ * @desc Set options, daemon will handle option setting.
+ */
+resourced_ret_c set_resourced_options(const resourced_options *options);
+
+/**
+ * @desc Obtain performance control options.
+ */
+resourced_ret_c get_resourced_options(resourced_options *options);
+
+/**
+ * @desc 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
+ */
+resourced_ret_c set_datausage_quota(const char *app_id,
+                             const data_usage_quota *quota);
+
+/**
+ * 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.
+ *
+ * @brief Data usage enumerate function
+ */
+resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
+                            data_usage_info_cb info_cb, void *user_data);
+
+/**
+ * The callback is called for each application that restricted now
+ *
+ * @brief Restrictions enumerate function
+ */
+resourced_ret_c restrictions_foreach(resourced_restriction_cb restriction_cb,
+                               void *user_data);
+
+/**
+ * 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.
+ *
+ * @brief Data usage details enumerate function
+ */
+resourced_ret_c data_usage_details_foreach(const char *app_id,
+                                          data_usage_selection_rule *rule,
+                                          data_usage_info_cb info_cb,
+                                          void *user_data);
+
+/**
+ * @desc This function registering callback which invokes per every packet.
+ *     Function creates new reading thread and returns.
+ */
+resourced_ret_c register_net_activity_cb(net_activity_cb activity_cb);
+
+/**
+ * @desc This function updates the resourced counters and stores in the database
+ */
+resourced_ret_c resourced_update_statistics(void);
+
+resourced_ret_c get_restriction_state(const char *pkg_id,
+       resourced_iface_type iftype, resourced_restriction_state *state);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RESOURCED_DATA_USAGE_H_ */
index d9b3a8a..fa759b7 100644 (file)
@@ -259,6 +259,12 @@ resourced_ret_c proc_cgroup_inactive(pid_t pid);
 resourced_ret_c proc_group_change_status(int type, pid_t pid, char* app_id);
 
 /**
+ * @desc Send process launch request
+ */
+resourced_ret_c proc_cgroup_launch(int type, pid_t pid, char* app_id, char* pkg_id);
+
+
+/**
  * @brief sweep memory about background processes
  *
  * @return return num of swept processes
diff --git a/include/rd-network.h b/include/rd-network.h
new file mode 100755 (executable)
index 0000000..c2c9f00
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * 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 system-resource 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__
index 51f2299..d9031a9 100644 (file)
  *  Created on: May 30, 2012
  */
 
-#ifndef _RESOURCED_H_
-#define _RESOURCED_H_
+#ifndef _SYSTEM_RESOURCE_RESOURCED_H_
+#define _SYSTEM_RESOURCE_RESOURCED_H_
 
 #include <sys/types.h>
-#include <signal.h>
-
-#define RESOURCED_ALL_APP "RESOURCED_ALL_APPLICATION_IDENTIFIER"
-#define TETHERING_APP_NAME "RESOURCED_TETHERING_APPLICATION_IDENTIFIER"
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-struct daemon_opts {
-       sig_atomic_t start_daemon;
-};
+#define RESOURCED_ALL_APP "RESOURCED_ALL_APPLICATION_IDENTIFIER"
+#define TETHERING_APP_NAME "RESOURCED_TETHERING_APPLICATION_IDENTIFIER"
 
-/**
- * @brief State of the monitored process
- */
-typedef enum {
-       RESOURCED_STATE_UNKNOWN = 0,
-       RESOURCED_STATE_FOREGROUND = 1 << 1,            /** < foreground state */
-       RESOURCED_STATE_BACKGROUND = 1 << 2,            /** < background state */
-       RESOURCED_STATE_LAST_ELEM = 1 << 3
-} resourced_state_t;
 
 /**
  * @brief return code of the rsml's function
  */
 typedef enum {
-       RESOURCED_ERROR_NONMONITOR = -8,                /** < Process don't show watchdog popup */
+       RESOURCED_ERROR_NONMONITOR = -9,                /** < Process don't show watchdog popup */
+       RESOURCED_ERROR_NONFREEZABLE = -8,              /** < Process is nonfrizable */
        RESOURCED_ERROR_NOTIMPL = -7,            /**< Not implemented yet error */
        RESOURCED_ERROR_UNINITIALIZED = -6,      /**< Cgroup doen't
                                           mounted or daemon not started */
@@ -72,16 +59,26 @@ typedef enum {
 #define RESOURCED_ERROR_OK RESOURCED_ERROR_NONE
 
 /**
- * @desc Description of the boolean option for enabling/disabling some behaviar
+ * @brief return type of the counters callback
  */
 typedef enum {
-       RESOURCED_OPTION_UNDEF,
-       RESOURCED_OPTION_ENABLE,
-       RESOURCED_OPTION_DISABLE
-} resourced_option_state;
+       RESOURCED_CANCEL = 0,                   /**< cancel */
+       RESOURCED_CONTINUE = 1,         /**< continue */
+} resourced_cb_ret;
+
+/**
+ * @desc 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.
+ * @param app_id[in] - application identifier, it's package name now
+ * @param pid - pid to put in to cgroup, or self pid of 0
+ * @return 0 if success or error code
+ */
+resourced_ret_c join_app_performance(const char *app_id, const pid_t pid);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* _RESOURCED_H_ */
+#endif /* _SYSTEM_RESOURCE_RESOURCED_H_ */
diff --git a/libresourced.manifest b/libresourced.manifest
new file mode 100644 (file)
index 0000000..3256181
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+<request>
+       <domain name="_"/>
+</request>
+</manifest>
diff --git a/libresourced.pc.in b/libresourced.pc.in
new file mode 100644 (file)
index 0000000..bf25f8a
--- /dev/null
@@ -0,0 +1,15 @@
+# Package Information for pkg-config
+#
+# Copyright (c) 2014 Samsung Electronics Co., Ltd.
+# All rights reserved.
+#
+
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_PROVIDED_LIBS@
+Cflags: @PC_CFLAGS@
diff --git a/packaging/add_test_net_activity.patch b/packaging/add_test_net_activity.patch
new file mode 100644 (file)
index 0000000..df5c1ef
--- /dev/null
@@ -0,0 +1,44 @@
+diff --git a/CMakeLists/resourced.txt b/CMakeLists/resourced.txt
+index f0b6f36..856c387 100644
+--- a/CMakeLists/resourced.txt
++++ b/CMakeLists/resourced.txt
+@@ -108,3 +108,17 @@ INSTALL(FILES ${DATA_DIR}/resourced
+   PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE WORLD_READ)
+ INSTALL(FILES ${DATA_DIR}/traffic_db.sql
+   DESTINATION /usr/share)
++
++IF("${CMAKE_BUILD_TYPE}" STREQUAL  "DEBUG")
++      SET(NET_ACTIVITY_PROJECT test_net_activity)
++      ADD_EXECUTABLE(${NET_ACTIVITY_PROJECT}
++              ${UTILS_SOURCE_DIR}/test-net-activity.c)
++      TARGET_LINK_LIBRARIES(${NET_ACTIVITY_PROJECT} ${daemon_pkgs_LDFLAGS}
++              resourced)
++      INSTALL(FILES ${NET_ACTIVITY_PROJECT}
++              DESTINATION ${MAKE_INSTALL_PREFIX}/usr/bin
++              PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE WORLD_EXECUTE)
++
++ENDIF()
++
++
+
+diff --git a/packaging/system-resource.spec b/packaging/system-resource.spec
+index cad7917..bc90f26 100644
+--- a/packaging/system-resource.spec
++++ b/packaging/system-resource.spec
+@@ -73,7 +73,7 @@ echo "\
+ #define MAJOR_VERSION ${MAJORVER}
+ #define PATCH_VERSION ${PATCHVER}" > src/common/version.h
+-cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} -DCMAKE_BUILD_TYPE=Release \
++cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} -DCMAKE_BUILD_TYPE=DEBUG \
+       -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}
+@@ -149,6 +149,7 @@ touch %{exclude_list_opt_full_path}
+ %config(noreplace) %attr(660,root,app) %{database_full_path}
+ %config(noreplace) %attr(660,root,app) %{database_full_path}-journal
+ /usr/bin/datausagetool
++/usr/bin/test_net_activity
+ %config %{_sysconfdir}/dbus-1/system.d/resourced.conf
+ %{_libdir}/systemd/system/resourced.service
+ %{_libdir}/systemd/system/multi-user.target.wants/resourced.service
diff --git a/packaging/resourced-cpucgroup.service b/packaging/resourced-cpucgroup.service
new file mode 100644 (file)
index 0000000..8db5ad7
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=make cpucgroup
+After=graphical.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/resourced-cpucgroup.sh
+
+[Install]
+WantedBy=graphical.target
diff --git a/packaging/resourced-logging.service b/packaging/resourced-logging.service
new file mode 100644 (file)
index 0000000..fe0b64d
--- /dev/null
@@ -0,0 +1,11 @@
+[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-zram.service b/packaging/resourced-zram.service
new file mode 100644 (file)
index 0000000..0ee4c1c
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=prepare zram
+After=default.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/resourced-zram.sh
+
+[Install]
+WantedBy=graphical.target
index ff2503d..c9454bc 100644 (file)
@@ -4,9 +4,14 @@ After=tizen-system.target
 Wants=tizen-system.target
 
 [Service]
-Type=simple
+Type=notify
 EnvironmentFile=/run/tizen-mobile-env
-ExecStart=/usr/bin/resourced -s 1
+Environment="CGROUP_MEMORY_SWAP=/sys/fs/cgroup/memory/swap"
+Environment="SWAPFILE=/dev/zram0"
+ExecStartPre=-/bin/mkdir -pm 755 $CGROUP_MEMORY_SWAP
+ExecStartPre=-/bin/sh -c "/bin/echo 3 > $CGROUP_MEMORY_SWAP/memory.move_charge_at_immigrate"
+ExecStart=/usr/bin/resourced -s 1 -u 20 -c swapon
+ExecStopPost=-/sbin/swapoff $SWAPFILE
 Restart=always
 RestartSec=0
 
diff --git a/packaging/resourced.spec b/packaging/resourced.spec
deleted file mode 100644 (file)
index 0ee08aa..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-Name:       system-resource
-Summary:    System Resource Daemon
-Version:    0.0.1
-Release:    1
-Group:      System/Management
-License:    Apache-2.0
-Source0:    %{name}-%{version}.tar.gz
-Source1:    resourced.service
-
-%define powertop_state OFF
-%define exclude_list_opt_full_path /opt/usr/etc/_exclude_list_file_name_
-
-
-BuildRequires:  cmake
-BuildRequires:  pkgconfig(glib-2.0)
-BuildRequires:  pkgconfig(dlog)
-BuildRequires:  pkgconfig(sqlite3)
-BuildRequires:  pkgconfig(vconf)
-BuildRequires:  pkgconfig(vconf-internal-keys)
-BuildRequires:  pkgconfig(ecore)
-BuildRequires:  pkgconfig(x11)
-BuildRequires:  pkgconfig(ecore-x)
-BuildRequires:  pkgconfig(utilX)
-BuildRequires:  pkgconfig(ecore-input)
-BuildRequires:  pkgconfig(ecore-file)
-BuildRequires:  pkgconfig(edbus)
-
-Requires(post): /sbin/ldconfig
-Requires(postun): /sbin/ldconfig
-
-%description
-System Resource Daemon to manage memory and process state
-
-%package devel
-Summary:  System Resource Information (Development)
-Group:    System/Development
-Requires: %{name} = %{version}-%{release}
-
-%description devel
-Development package for Resourced Daemon
-to manage memory and process state
-
-%if %{?powertop_state} == ON
-%package powertop-wrapper
-Summary: Powertop-wrapper libray
-Group:   System/Libraries
-
-%description powertop-wrapper
-Powertop control library
-%endif
-
-%prep
-%setup -q
-
-%build
-MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
-MINORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $2}'`
-PATCHVER=`echo %{version} | awk 'BEGIN {FS="."}{print $3}'`
-echo "\
-/* That file was generated automaticaly. Don't edit it */
-#define MINOR_VERSION ${MINORVER}
-#define MAJOR_VERSION ${MAJORVER}
-#define PATCH_VERSION ${PATCHVER}" > src/common/version.h
-
-%if 0%{?tizen_build_binary_release_type_eng}
-       CFLAGS+=" -DTIZEN_ENGINEER_MODE"
-%endif
-
-cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} -DCMAKE_BUILD_TYPE=Release \
-       -DEXCLUDE_LIST_OPT_FULL_PATH=%{exclude_list_opt_full_path} \
-       -DPOWERTOP_MODULE=%{powertop_state}
-
-make %{?jobs:-j%jobs}
-
-%install
-rm -rf %{buildroot}
-mkdir -p %{buildroot}/usr/share/license
-cp -f LICENSE %{buildroot}/usr/share/license/%{name}
-
-%if %{?powertop_state} == ON
-cp -f LICENSE %{buildroot}/usr/share/license/%{name}-powertop-wrapper
-%endif
-
-%make_install
-
-mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants
-install -m 0644 %SOURCE1 %{buildroot}%{_libdir}/systemd/system/resourced.service
-ln -s ../resourced.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/resourced.service
-
-#powertop-wrapper part
-%if %{?powertop_state} == ON
-mkdir -p %{buildroot}/usr/share/powertop-wrapper/
-cp -p %_builddir/%name-%version/src/powertop-wrapper/header.html %{buildroot}/usr/share/powertop-wrapper
-%endif
-
-%post
-/sbin/ldconfig
-
-mkdir -p /opt/usr/etc
-
-if [ "$1" = "2" ]; then # upgrade begins
-       systemctl start resourced.service
-fi
-
-%postun
-/sbin/ldconfig
-
-%if %{?powertop_state} == ON
-%post powertop-wrapper -p /sbin/ldconfig
-%postun powertop-wrapper -p /sbin/ldconfig
-%endif
-
-%files
-%manifest resourced.manifest
-%{_libdir}/libproc-stat.so.*
-/usr/share/license/%{name}
-%attr(-,root, root) %{_bindir}/resourced
-%config %{_sysconfdir}/dbus-1/system.d/resourced.conf
-%{_libdir}/systemd/system/resourced.service
-%{_libdir}/systemd/system/multi-user.target.wants/resourced.service
-%config /etc/resourced/memory.conf
-
-%if %{?powertop_state} == ON
-%files powertop-wrapper
-%manifest powertop-wrapper.manifest
-%{_libdir}/libpowertop-wrapper.so.*
-/usr/share/powertop-wrapper/header.html
-/usr/share/license/%{name}-powertop-wrapper
-%endif
-
-%files devel
-%{_libdir}/pkgconfig/*.pc
-%{_includedir}/system/proc_stat.h
-%{_libdir}/libproc-stat.so
-%{_includedir}/system/resourced.h
-
-%if %{?powertop_state} == ON
-#powertop-wrapper part
-%{_includedir}/system/powertop-dapi.h
-%{_libdir}/libpowertop-wrapper.so
-%endif
diff --git a/packaging/resourced_swapoff.service b/packaging/resourced_swapoff.service
new file mode 100644 (file)
index 0000000..c07025d
--- /dev/null
@@ -0,0 +1,14 @@
+[Unit]
+Description=Resource management daemon
+After=tizen-system.target
+Wants=tizen-system.target
+
+[Service]
+Type=simple
+EnvironmentFile=/run/tizen-mobile-env
+ExecStart=/usr/bin/resourced -s 1 -u 60
+Restart=always
+RestartSec=0
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/system-resource.spec b/packaging/system-resource.spec
new file mode 100644 (file)
index 0000000..0201166
--- /dev/null
@@ -0,0 +1,299 @@
+Name:       system-resource
+Summary:    System Resource Information
+Version:    0.2.86
+Release:    0
+VCS:        magnolia/kernel/api/system-resource#submit/master/20131010.041510-19-gcf6121a4bcce9c122d4ea05fa9974ec7bac227d8
+Group:      System/Libraries
+License:    Apache License, Version 2.0
+Source0:    %{name}-%{version}.tar.gz
+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 logging_memory OFF
+%define logging_cpu OFF
+%define memory_module ON
+%define memory_cgroup OFF
+
+%if "%{?tizen_profile_name}" == "mobile"
+       %define swap_module OFF
+       %define network_state ON
+       %define network_service OFF
+       %define telephony_feature OFF
+       %define tethering_feature OFF
+
+%endif
+
+%if "%{?tizen_profile_name}" == "wearable"
+       %define swap_module OFF
+       %define network_state ON
+       %define network_service OFF
+       %define telephony_feature OFF
+
+%endif
+
+%if 0%{?tizen_build_binary_release_type_eng}
+       %define memory_eng ON
+%else
+       %define memory_eng OFF
+%endif
+
+%define exclude_list_file_name resourced_proc_exclude.ini
+%define exclude_list_full_path /usr/etc/%{exclude_list_file_name}
+%define exclude_list_opt_full_path /opt/usr/etc/%{exclude_list_file_name}
+%define database_full_path /opt/usr/dbspace/.resourced-datausage.db
+
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(sqlite3)
+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(journal)
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires: system-resource-resourced = %{version}-%{release}
+Requires: libresourced = %{version}-%{release}
+
+%if %{?logging_module} == ON
+BuildRequires:  pkgconfig(libsystemd-journal)
+%endif
+
+%description
+
+%package resourced
+Summary: Resource Daemon
+Group:   System/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description resourced
+Resource Daemon
+
+%package -n libresourced
+Summary: Resource Daemon Library
+Group:   System/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description -n libresourced
+Resource Daemon Library
+
+%package -n libresourced-devel
+Summary: Resource Daemon Library (Development)
+Group:   System/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description -n libresourced-devel
+Resource Daemon Library (Development)
+
+%prep
+%setup -q
+
+%build
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+MINORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $2}'`
+PATCHVER=`echo %{version} | awk 'BEGIN {FS="."}{print $3}'`
+echo "\
+/* That file was generated automaticaly. Don't edit it */
+#define MINOR_VERSION ${MINORVER}
+#define MAJOR_VERSION ${MAJORVER}
+#define PATCH_VERSION ${PATCHVER}" > src/common/version.h
+
+%if 0%{?tizen_build_binary_release_type_eng}
+       CFLAGS+=" -DTIZEN_ENGINEER_MODE"
+%endif
+
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+
+cmake . -DCMAKE_INSTALL_PREFIX=/usr -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} -DNETWORK_SERVICE=%{network_service} \
+       -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}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/usr/share/license
+cp -f LICENSE %{buildroot}/usr/share/license/%{name}
+cp -f LICENSE %{buildroot}/usr/share/license/%{name}-resourced
+cp -f LICENSE %{buildroot}/usr/share/license/libresourced
+
+%make_install
+
+%if %{?network_state} == ON
+       mkdir -p %{buildroot}/opt/usr/dbspace
+       sqlite3 %{buildroot}%{database_full_path} < %{buildroot}/usr/share/traffic_db.sql
+       rm %{buildroot}/usr/share/traffic_db.sql
+%endif
+
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants
+%if %{?swap_module} == ON
+install -m 0644 %SOURCE1 %{buildroot}%{_libdir}/systemd/system/resourced.service
+ln -s ../resourced.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/resourced.service
+
+mkdir -p %{buildroot}%{_libdir}/systemd/system/graphical.target.wants
+install -m 0644 %SOURCE2 %{buildroot}%{_libdir}/systemd/system/resourced-zram.service
+ln -s ../resourced-zram.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/resourced-zram.service
+%else
+install -m 0644 %SOURCE5 %{buildroot}%{_libdir}/systemd/system/resourced.service
+ln -s ../resourced.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/resourced.service
+%endif
+
+%if %{?cpu_module} == OFF
+mkdir -p %{buildroot}%{_libdir}/systemd/system/graphical.target.wants
+install -m 0644 %SOURCE6 %{buildroot}%{_libdir}/systemd/system/resourced-cpucgroup.service
+ln -s ../resourced-cpucgroup.service %{buildroot}%{_libdir}/systemd/system/graphical.target.wants/resourced-cpucgroup.service
+%endif
+
+#powertop-wrapper part
+%if %{?powertop_state} == ON
+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
+fi
+
+%post -p /sbin/ldconfig
+
+%post resourced
+
+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
+}
+
+%if %{?network_state} == ON
+       init_vconf
+%endif
+#install init.d script
+mkdir -p /opt/usr/etc
+#make empty dynamic exclude list for first installation
+touch %{exclude_list_opt_full_path}
+
+if [ "$1" = "2" ]; then # upgrade begins
+       systemctl start resourced.service
+fi
+
+%postun -p /sbin/ldconfig
+
+%files
+/usr/share/license/%{name}
+%manifest system-resource.manifest
+%files resourced
+/usr/share/license/%{name}-resourced
+%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
+       %manifest resourced.manifest
+%else
+%manifest resourced_nodb.manifest
+%endif
+%config %{_sysconfdir}/dbus-1/system.d/resourced.conf
+%{_libdir}/systemd/system/resourced.service
+%{_libdir}/systemd/system/multi-user.target.wants/resourced.service
+/etc/resourced/memory.conf
+%if %{?cpu_module} == ON
+/etc/resourced/cpu.conf
+%else
+%{_bindir}/resourced-cpucgroup.sh
+%{_libdir}/systemd/system/resourced-cpucgroup.service
+%{_libdir}/systemd/system/graphical.target.wants/resourced-cpucgroup.service
+%endif
+%if %{?swap_module} == ON
+%{_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
+/etc/resourced/vip-process.conf
+%attr(-,root, root) %{_bindir}/vip-release-agent
+%endif
+%if %{?timer_slack} == ON
+/etc/resourced/timer-slack.conf
+%endif
+%{exclude_list_full_path}
+%if %{?powertop_state} == ON
+/usr/share/powertop-wrapper/header.html
+%endif
+
+#memps
+%attr(-,root, root) %{_bindir}/memps
+
+%files -n libresourced
+%manifest libresourced.manifest
+%defattr(-,root,root,-)
+/usr/share/license/libresourced
+#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.*
+%endif
+
+%files -n libresourced-devel
+%defattr(-,root,root,-)
+%{_libdir}/pkgconfig/*.pc
+%{_includedir}/system/resourced.h
+#proc-stat part
+%{_includedir}/system/proc_stat.h
+%{_libdir}/libproc-stat.so
+#network part
+%if %{?network_state} != OFF
+%{_includedir}/system/data_usage.h
+%{_includedir}/system/rd-network.h
+%{_libdir}/libresourced.so
+%{_libdir}/librd-network.so
+/etc/resourced/network.conf
+%endif
+#powertop-wrapper part
+%if %{?powertop_state} == ON
+%{_includedir}/system/powertop-dapi.h
+%{_libdir}/libpowertop-wrapper.so
+%endif
diff --git a/powertop-wrapper.manifest b/powertop-wrapper.manifest
deleted file mode 100644 (file)
index f5a44ec..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<manifest>
-        <request>
-                <domain name="_"/>
-        </request>
-</manifest>
diff --git a/proc-stat.manifest b/proc-stat.manifest
deleted file mode 100644 (file)
index f5a44ec..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<manifest>
-        <request>
-                <domain name="_"/>
-        </request>
-</manifest>
index 12b9307..f8558b2 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
-       <policy context="default">
+               <policy context="default">
         <deny own="org.tizen.resourced"/>
     </policy>
     <policy user="root">
index f5a44ec..56400ee 100644 (file)
@@ -1,5 +1,14 @@
 <manifest>
-        <request>
-                <domain name="_"/>
-        </request>
+       <define>
+               <domain name="resourced"/>
+               <provide>
+                       <label name="resourced::db"/>
+               </provide>
+       </define>
+       <assign>
+               <filesystem path="/opt/usr/dbspace/.resourced-datausage.db*" label="resourced::db"/>
+       </assign>
+       <request>
+               <domain name="resourced"/>
+       </request>
 </manifest>
diff --git a/resourced.rule b/resourced.rule
new file mode 100644 (file)
index 0000000..d6cbe41
--- /dev/null
@@ -0,0 +1,3 @@
+resourced com.samsung.setting::private r
+resourced system::vconf_inhouse rw
+resourced system-apps r
\ No newline at end of file
diff --git a/resourced_nodb.manifest b/resourced_nodb.manifest
new file mode 100644 (file)
index 0000000..3256181
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+<request>
+       <domain name="_"/>
+</request>
+</manifest>
diff --git a/scripts/resourced-cpucgroup.sh b/scripts/resourced-cpucgroup.sh
new file mode 100644 (file)
index 0000000..053279f
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+CPU_CGROUP="/sys/fs/cgroup/cpu/background"
+CPU_SHARE="50"
+CPU_CONTROL_LIST="indicator net-config"
+
+/bin/mkdir -pm 755 $CPU_CGROUP
+echo $CPU_SHARE > $CPU_CGROUP/cpu.shares
+for list in $CPU_CONTROL_LIST; do
+        pid=`/usr/bin/pgrep $list`
+        if [ "z${pid}" != "z" ]; then
+                echo $pid > $CPU_CGROUP/cgroup.procs
+        fi
+done
+
diff --git a/scripts/resourced-zram.sh b/scripts/resourced-zram.sh
new file mode 100644 (file)
index 0000000..dd35014
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+FILE="/sys/block/zram0"
+SWAP="/dev/zram0"
+RATE="20"
+
+Mem=`cat /proc/meminfo | grep "MemTotal" | awk '{print $2}'`
+
+if [ $Mem -lt 200000 ]; then
+        SIZE="8388608"
+elif [ $Mem -ge 200000 -a $Mem -lt 900000 ]; then
+        SIZE=$((Mem * RATE / 100 * 1024))
+elif [ $Mem -ge 900000 ]; then
+        SIZE="134217728"
+fi
+
+if [ ! -e $FILE ]; then
+       /sbin/modprobe zram num_devices=1
+fi
+/bin/echo $SIZE > $FILE/disksize
+/sbin/mkswap $SWAP
diff --git a/src/common/app-stat.h b/src/common/app-stat.h
new file mode 100644 (file)
index 0000000..6818fad
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  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: app-stat.h
+ *
+ *  @desc Application stat entity
+ *  @version 1.0
+ *
+ */
+
+#ifndef _RESOURCED_APPLICATION_STAT_H_
+#define _RESOURCED_APPLICATION_STAT_H_
+
+#include <netinet/in.h>
+#include <glib.h>
+#include <sys/types.h>
+
+#include "const.h"
+#include "data_usage.h"
+#include "daemon-options.h"
+#include "transmission.h"
+
+#define RSML_UNKNOWN_CLASSID 1
+
+/*
+* General structure containing information for storing
+* application_id - package name as unique application identifier
+* snd_count - sent bytes
+* rcv_count - received bytes
+* pid - process identifier
+* ifindex - network interface index, iftype holds in key @see resourced_iface_type
+* is_roaming - is traffic consumed at roaming, @see resourced_roaming_type
+*/
+struct application_stat {
+       char *application_id;
+       uint32_t snd_count;
+       uint32_t rcv_count;
+       uint32_t delta_snd;
+       uint32_t delta_rcv;
+
+       pid_t pid;
+       int ifindex;
+       resourced_roaming_type is_roaming;
+};
+
+/*
+* Structure for holding serialized data from kernel @see traffic_event
+*/
+struct traffic_stat {
+       unsigned long bytes;
+       int ifindex;
+};
+
+struct classid_iftype_key
+{
+       u_int32_t classid;
+       int iftype;
+       char ifname[MAX_NAME_LENGTH];
+};
+
+typedef GTree traffic_stat_tree;
+
+struct application_stat_tree {
+       GTree *tree;
+       time_t last_touch_time;
+       pthread_rwlock_t guard;
+};
+
+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);
+
+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/common/appid-helper.c b/src/common/appid-helper.c
new file mode 100644 (file)
index 0000000..091a104
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#define BASE_NAME_PREFIX "com.samsung."
+#define DOT_DELIMETER '.'
+
+static int is_base_name(const char *appid)
+{
+       return strstr(appid, BASE_NAME_PREFIX) != NULL;
+}
+
+void extract_pkgname(const char *appid, char *pkgname,
+       const int pkgname_size)
+{
+       char *delim_pos; /* delimeter position */
+       size_t pkgname_res_size;
+
+       if (is_base_name(appid)) {
+               strncpy(pkgname, appid, pkgname_size);
+               return;
+       }
+
+       /* no a base name case try to dedicate pkg name */
+       delim_pos = strchr(appid, DOT_DELIMETER);
+       if (delim_pos) {
+               pkgname_res_size = abs(delim_pos - appid);
+               pkgname_res_size = pkgname_res_size > pkgname_size ?
+                       pkgname_size : pkgname_res_size;
+       } else
+               pkgname_res_size = pkgname_size -1;
+
+       strncpy(pkgname, appid, pkgname_res_size);
+       pkgname[pkgname_res_size] = '\0';
+}
diff --git a/src/common/appid-helper.h b/src/common/appid-helper.h
new file mode 100644 (file)
index 0000000..3558cc2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ *
+*/
+
+
+#define PKGNAME_SIZE MAX_NAME_SIZE
+
+/**
+ * Get package name from appid.
+ *     For base (rpm) packages it's the same name as appid,
+ *     For SDK (tpk) packages it's 10 alpha digit before first .(dot)
+ *     @param appid - given appid
+ *     @param pkgname - out package name
+ *     @pkgname_size - size of pkgname given buffer
+ **/
+void extract_pkgname(const char *appid, char *pkgname, const int pkgname_size);
diff --git a/src/common/cgroup.c b/src/common/cgroup.c
new file mode 100644 (file)
index 0000000..9958f22
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * Cgroup creation implementation
+ */
+
+#include "cgroup.h"
+#include "const.h"
+#include "macro.h"
+#include "resourced.h"
+#include "trace.h"
+#include "file-helper.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>             /*mkdirat */
+#include <glib.h>
+#include <limits.h>
+#include <sys/stat.h>          /*mkdirat */
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>              /*time function */
+#include <unistd.h>
+#include <sys/mount.h>
+
+static int is_cgroup_exists(const char *cgroup_full_path)
+{
+       struct stat stat_buf;
+       return stat(cgroup_full_path, &stat_buf) == 0;
+}
+
+static int create_cgroup(const char *cgroup_full_path)
+{
+       if (mkdir (cgroup_full_path,
+               S_IRUSR | S_IWUSR | S_IRGRP) < 0)
+               return -errno;
+
+       return 0;
+}
+
+/*
+ * @desc place pid to cgroup.procs file
+ * @return 0 in case of success, errno value in case of failure
+ */
+resourced_ret_c place_pid_to_cgroup_by_fullpath(const char *cgroup_full_path,
+       const int pid)
+{
+       int ret = cgroup_write_node(cgroup_full_path, CGROUP_FILE_NAME,
+               (u_int32_t)pid);
+
+       ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+               "Failed place all pid to cgroup %s, error %s",
+                       cgroup_full_path, strerror(errno));
+       return RESOURCED_ERROR_NONE;
+}
+
+resourced_ret_c place_pid_to_cgroup(const char *cgroup_subsystem,
+       const char *cgroup_name, const int pid)
+{
+       char buf[MAX_PATH_LENGTH];
+       snprintf(buf, sizeof(buf), "%s/%s", cgroup_subsystem, cgroup_name);
+       return place_pid_to_cgroup_by_fullpath(buf, pid);
+}
+
+int cgroup_write_node(const char *cgroup_name,
+               const char *file_name, unsigned int value)
+{
+       char buf[MAX_PATH_LENGTH];
+       snprintf(buf, sizeof(buf), "%s%s", cgroup_name, file_name);
+       _SD("cgroup_buf %s, value %d\n", buf, value);
+       return fwrite_int(buf, value);
+}
+
+int cgroup_write_node_str(const char *cgroup_name,
+               const char *file_name, char* string)
+{
+       char buf[MAX_PATH_LENGTH];
+       snprintf(buf, sizeof(buf), "%s%s", cgroup_name, file_name);
+       _SD("cgroup_buf %s, string %s\n", buf, string);
+       return fwrite_str(buf, string);
+}
+
+int cgroup_read_node(const char *cgroup_name,
+               const char *file_name, unsigned int *value)
+{
+       char buf[MAX_PATH_LENGTH];
+       snprintf(buf, sizeof(buf), "%s%s", cgroup_name, file_name);
+       _SD("cgroup_buf %s, value %d\n", buf, *value);
+       return fread_int(buf, value);
+}
+
+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);
+       ret_value_msg_if(ret > sizeof(buf), RESOURCED_ERROR_FAIL,
+               "Not enought buffer size for %s%s", parentdir, cgroup_name);
+
+       cgroup_exists = is_cgroup_exists(buf);
+       if (!cgroup_exists) {
+               ret = create_cgroup(buf);
+               ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+                       "cpu cgroup create fail : err %d, name %s", errno,
+                               cgroup_name);
+       }
+
+       if (exists)
+               *exists = cgroup_exists;
+
+       return RESOURCED_ERROR_NONE;
+}
+
+int mount_cgroup_subsystem(char* source, char* mount_point, char* opts)
+{
+       return mount(source, mount_point, "cgroup",
+                   MS_NODEV | MS_NOSUID | MS_NOEXEC, opts);
+}
+
diff --git a/src/common/cgroup.h b/src/common/cgroup.h
new file mode 100644 (file)
index 0000000..c57bf67
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <resourced.h>
+#include <sys/types.h>
+
+/*
+ * Cgroup creation interface
+ */
+
+#ifndef _CGROUP_LIBRARY_CGROUP_H_
+#define _CGROUP_LIBRARY_CGROUP_H_
+
+#define DEFAULT_CGROUP         "/sys/fs/cgroup"
+
+/**
+ * @desc Get one unsigned int value from cgroup
+ * @param cgroup_name - cgroup path
+ * @param file_name - cgroup content to write
+ * @param value - out parameter, value to fill
+ * @return negative value if error
+*/
+int cgroup_read_node(const char *cgroup_name,
+               const char *file_name, unsigned int *value);
+
+/**
+ * @desc Put value to cgroup,
+ * @param cgroup_name - cgroup path
+ * @param file_name - cgroup content to write
+ * @param value - data to write
+ * @return negative value if error
+ */
+int cgroup_write_node(const char *cgroup_name,  const char *file_name, unsigned int value);
+
+/**
+ * @desc Put value to cgroup,
+ * @param cgroup_name - cgroup path
+ * @param file_name - cgroup content to write
+ * @param string -string to write
+ * @return negative value if error
+ */
+int cgroup_write_node_str(const char *cgroup_name,
+               const char *file_name, char* string);
+
+/**
+ * @desc make cgroup,
+ * @param parentdir - parent cgroup path
+ * @param cgroup_name - cgroup subdirectory to write
+ * @param cgroup_exists - 1 if subdir already exists, NULL pointer is possible
+ * as formal argument, in this case it will not be filled
+ * @return negative value if error
+ */
+int make_cgroup_subdir(char* parentdir, char* cgroup_name, int *cgroup_exists);
+
+/**
+ * @desc mount cgroup,
+ * @param source -cgroup name
+ * @param mount_point - cgroup path
+ * @param opts - mount options
+ * @return negative value if error
+ */
+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
+ * @return negative value if error
+ */
+resourced_ret_c place_pid_to_cgroup(const char *cgroup_subsystem,
+       const char *cgroup_name, const int pid);
+
+resourced_ret_c place_pid_to_cgroup_by_fullpath(const char *cgroup_full_path,
+       const int pid);
+
+#endif /*_CGROUP_LIBRARY_CGROUP_H_*/
index f1d55a4..a25e902 100644 (file)
@@ -10,5 +10,8 @@
 
 #cmakedefine MINOR_VERSION ${MINOR_VERSION}
 #cmakedefine MAJOR_VERSION ${MAJOR_VERSION}
+#cmakedefine CONFIG_DATAUSAGE_NFACCT @CONFIG_DATAUSAGE_NFACCT@
+#cmakedefine TETHERING_FEATURE  @TETHERING_FEATURE@
+
 
 #endif /* _CONFIG_H_GENERATED*/
index cf86028..4c94396 100644 (file)
@@ -1,5 +1,32 @@
-#ifndef _RESMAN_CONST_H
-#define _RESMAN_CONST_H
+/*
+ *  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: const.h
+ *
+ *  @desc Application stat entity
+ *  @version 1.0
+ *
+ */
+
+#ifndef _RESOURCED_CONST_H
+#define _RESOURCED_CONST_H
 
 #define TASK_FILE_NAME "/tasks"
 #define CGROUP_FILE_NAME "/cgroup.procs"
 
 #define COMMA_DELIMETER ","
 
-#define API __attribute__((visibility("default")))
+#define COUNTER_UPDATE_PERIOD 60
+#define FLUSH_PERIOD 60
+#define STORE_DELAY_INTERVAL 1
+
+#define NONE_QUOTA_ID 0
+
+#define TIME_TO_SAFE_DATA 1 /* one second */
+
+/*
+ * @desc reserved classid enums
+ * internal structure, we don't provide it externally
+*/
+enum resourced_reserved_classid {
+       RESOURCED_UNKNOWN_CLASSID,
+       RESOURCED_ALL_APP_CLASSID,              /**< kernel expects 1 for
+                                               handling restriction for all
+                                               applications  */
+       RESOURCED_TETHERING_APP_CLASSID,        /**< it uses in user space logic
+                                               for counting tethering traffic */
+       RESOURCED_RESERVED_CLASSID_MAX,
+};
+
+enum resourced_counter_state {
+       RESOURCED_DEFAULT_STATE = 0,
+       RESOURCED_FORCIBLY_FLUSH_STATE = 1 << 1,
+       RESOURCED_FORCIBLY_QUIT_STATE = 1 << 2,
+       RESOURCED_NET_BLOCKED_STATE = 1 << 3,
+};
 
-#endif /* _RESMAN_CONST_H */
+#endif /* _RESOURCED_CONST_H */
diff --git a/src/common/daemon-options.h b/src/common/daemon-options.h
new file mode 100644 (file)
index 0000000..a046dd6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 - 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: daemon-options.h
+ *
+ *  @desc Entity for working with daemon options
+ *
+ */
+
+#ifndef _RESOURCED_DATAUSAGE_DAEMON_OPTIONS_H
+#define _RESOURCED_DATAUSAGE_DAEMON_OPTIONS_H
+
+
+#include <sys/types.h>
+#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;
+       sig_atomic_t flush_period;
+       sig_atomic_t state;
+       sig_atomic_t enable_swap;
+};
+
+/* TODO remove */
+void load_daemon_opts(struct daemon_opts *daemon_options);
+
+#endif /* _RESOURCED_DATAUSAGE_DAEMON_OPTIONS_H */
index a16da62..85b6f27 100644 (file)
@@ -39,8 +39,10 @@ struct edbus_list{
 };
 
 static struct edbus_object edbus_objects[] = {
+       { RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP   , NULL, NULL },
        { RESOURCED_PATH_OOM, RESOURCED_INTERFACE_OOM, NULL, NULL },
        { RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS, NULL, NULL },
+       { RESOURCED_PATH_NETWORK, RESOURCED_INTERFACE_NETWORK, NULL, NULL },
        /* Add new object & interface here*/
 };
 
@@ -111,6 +113,17 @@ static int append_variant(DBusMessageIter *iter,
        return 0;
 }
 
+void serialize_params(char *params[], size_t n, ...)
+{
+       va_list va;
+       int i = 0;
+       va_start(va, n);
+       for (i = 0; i < n; ++i) {
+               params[i] = va_arg(va, char *);
+       }
+       va_end(va);
+}
+
 DBusMessage *dbus_method_sync(const char *dest, const char *path,
                const char *interface, const char *method,
                const char *sig, char *param[])
@@ -160,6 +173,44 @@ DBusMessage *dbus_method_sync(const char *dest, const char *path,
        return reply;
 }
 
+int dbus_method_async(const char *dest, const char *path,
+               const char *interface, const char *method,
+               const char *sig, char *param[])
+{
+       DBusConnection *conn;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       int ret;
+
+       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!conn) {
+               _E("dbus_bus_get error");
+               return -EPERM;
+       }
+
+       msg = dbus_message_new_method_call(dest, path, interface, method);
+       if (!msg) {
+               _E("dbus_message_new_method_call(%s:%s-%s)", path, interface, method);
+               return -EBADMSG;
+       }
+
+       dbus_message_iter_init_append(msg, &iter);
+       ret = append_variant(&iter, sig, param);
+       if (ret < 0) {
+               _E("append_variant error(%d)", ret);
+               dbus_message_unref(msg);
+               return ret;
+       }
+
+       ret = dbus_connection_send(conn, msg, NULL);
+       dbus_message_unref(msg);
+       if (ret != TRUE) {
+               _E("dbus_connection_send error");
+               return -ECOMM;
+       }
+
+       return 0;
+}
 
 int register_edbus_interface(struct edbus_object *object)
 {
@@ -320,16 +371,23 @@ int register_edbus_signal_handler(const char *path, const char *interface,
                free(entry);
                return RESOURCED_ERROR_FAIL;
        }
-       return 0;
+       return RESOURCED_ERROR_NONE;
 }
 
 int broadcast_edbus_signal_str(const char *path, const char *interface,
                const char *name, const char *sig, char *param[])
 {
        DBusMessage *msg;
+       DBusConnection *conn;
        DBusMessageIter iter;
        int r;
 
+       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!conn) {
+               _E("dbus_bus_get error");
+               return -EPERM;
+       }
+
        msg = dbus_message_new_signal(path, interface, name);
        if (!msg) {
                _E("fail to allocate new %s.%s signal", interface, name);
@@ -343,28 +401,48 @@ int broadcast_edbus_signal_str(const char *path, const char *interface,
                return -EPERM;
        }
 
-       e_dbus_message_send(edbus_conn, msg, NULL, -1, NULL);
-
+       r = dbus_connection_send(conn, msg, NULL);
        dbus_message_unref(msg);
-       return 0;
+
+       if (r != TRUE) {
+               _E("dbus_connection_send error(%s:%s-%s)",
+                       path, interface, name);
+               return -ECOMM;
+       }
+
+       return RESOURCED_ERROR_NONE;
 }
 
 int broadcast_edbus_signal(const char *path, const char *interface,
                const char *name, int type, void *value)
 {
-       DBusMessage *signal = dbus_message_new_signal(path, interface, name);
+       DBusConnection *conn;
+       DBusMessage *msg = dbus_message_new_signal(path, interface, name);
+       int r;
 
-       if (!signal) {
+       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!conn) {
+               _E("dbus_bus_get error");
+               return -EPERM;
+       }
+
+       if (!msg) {
                _E("fail to allocate new %s.%s signal", interface, name);
                return RESOURCED_ERROR_FAIL;
        }
 
-       dbus_message_append_args(signal, type, value, DBUS_TYPE_INVALID);
+       dbus_message_append_args(msg, type, value, DBUS_TYPE_INVALID);
 
-       e_dbus_message_send(edbus_conn, signal, NULL, -1, NULL);
+       r = dbus_connection_send(conn, msg, NULL);
+       dbus_message_unref(msg);
+
+       if (r != TRUE) {
+               _E("dbus_connection_send error(%s:%s-%s)",
+                       path, interface, name);
+               return -ECOMM;
+       }
 
-       dbus_message_unref(signal);
-       return RESOURCED_ERROR_OK;
+       return RESOURCED_ERROR_NONE;
 }
 
 resourced_ret_c edbus_add_methods(const char *path,
@@ -398,9 +476,31 @@ resourced_ret_c edbus_add_methods(const char *path,
        return RESOURCED_ERROR_NONE;
 }
 
+static void request_name_cb(void *data, DBusMessage *msg, DBusError *error)
+{
+       DBusError err;
+       unsigned int val;
+       int r;
+
+       if (!msg) {
+               _D("invalid DBusMessage!");
+               return;
+       }
+
+       dbus_error_init(&err);
+       r = dbus_message_get_args(msg, &err, DBUS_TYPE_UINT32, &val, DBUS_TYPE_INVALID);
+       if (!r) {
+               _E("no message : [%s:%s]", err.name, err.message);
+               dbus_error_free(&err);
+               return;
+       }
+
+       _I("Request Name reply : %d", val);
+}
+
 void edbus_init(void)
 {
-       int retry = RESOURCED_ERROR_OK;
+       int retry = RESOURCED_ERROR_NONE;
        int i;
 retry_init:
        edbus_init_val = e_dbus_init();
@@ -427,7 +527,8 @@ retry_bus_get:
 
 retry_bus_request:
        retry = 0;
-       edbus_request_name = e_dbus_request_name(edbus_conn, BUS_NAME, 0, NULL, NULL);
+       edbus_request_name = e_dbus_request_name(edbus_conn, BUS_NAME,
+                       DBUS_NAME_FLAG_REPLACE_EXISTING, request_name_cb, NULL);
        if (edbus_request_name)
                goto register_objects;
        if (retry == EDBUS_INIT_RETRY_COUNT) {
index 4460596..e620521 100644 (file)
@@ -48,11 +48,41 @@ struct edbus_object {
 #define OBJECT_PATH            "/Org/Tizen/ResourceD"
 #define INTERFACE_NAME         BUS_NAME
 
-#define RESOURCED_PATH_OOM                             OBJECT_PATH"/Oom"
+/*
+ * The EDbus method to update the resourced counters
+ * Signal is generated after the database update
+ * and store new values of the counters
+ */
+#define RESOURCED_NETWORK_UPDATE               "Update"
+#define RESOURCED_NETWORK_UPDATE_FINISH        "UpdateFinish"
+#define RESOURCED_NETWORK_PROCESS_RESTRICTION  "ProcessRestriction"
+#define RESOURCED_NETWORK_CREATE_QUOTA         "CreateQuota"
+#define RESOURCED_NETWORK_REMOVE_QUOTA         "RemoveQuota"
+#define RESOURCED_NETWORK_JOIN_NET_STAT                "JoinNetStat"
+#define RESOURCED_NETWORK_GET_STATS            "GetStats"
+
+/*
+ * Core service
+ *   get/set swap status
+ *   operations about swap
+ */
+#define RESOURCED_PATH_SWAP            OBJECT_PATH"/Swap"
+#define RESOURCED_INTERFACE_SWAP       INTERFACE_NAME".swap"
+
+#define RESOURCED_PATH_OOM             OBJECT_PATH"/Oom"
 #define RESOURCED_INTERFACE_OOM                INTERFACE_NAME".oom"
 
-#define RESOURCED_PATH_PROCESS                 OBJECT_PATH"/Process"
-#define RESOURCED_INTERFACE_PROCESS            INTERFACE_NAME".process"
+#define RESOURCED_PATH_NETWORK         OBJECT_PATH"/Network"
+#define RESOURCED_INTERFACE_NETWORK    INTERFACE_NAME".network"
+
+#define RESOURCED_PATH_PROCESS         OBJECT_PATH"/Process"
+#define RESOURCED_INTERFACE_PROCESS    INTERFACE_NAME".process"
+
+/*
+ * Logging
+ */
+#define RESOURCED_PATH_LOGGING         OBJECT_PATH"/Logging"
+#define RESOURCED_INTERFACE_LOGGING    INTERFACE_NAME".logging"
 
 /*
  * System popup
@@ -71,6 +101,12 @@ struct edbus_object {
 #define DEVICED_PATH_PROCESS           "/Org/Tizen/System/DeviceD/Process"
 #define DEVICED_INTERFACE_PROCESS      DEVICED_BUS_NAME".Process"
 
+#define DEVICED_PATH_DISPLAY               "/Org/Tizen/System/DeviceD/Display"
+#define DEVICED_INTERFACE_DISPLAY      DEVICED_BUS_NAME".display"
+
+#define SIGNAL_LCD_ON  "LCDOn"
+#define SIGNAL_LCD_OFF "LCDOff"
+
 struct dbus_byte {
        char *data;
        int size;
@@ -78,10 +114,21 @@ struct dbus_byte {
 
 #define RETRY_MAX 5
 
+/*
+ * @desc helper function for filling params array
+ * That params array is used in dbus_method_sync/dbus_method_async
+ * */
+void serialize_params(char *params[], size_t n, ...);
+
+
 DBusMessage *dbus_method_sync(const char *dest, const char *path,
                const char *interface, const char *method,
                const char *sig, char *param[]);
 
+int dbus_method_async(const char *dest, const char *path,
+               const char *interface, const char *method,
+               const char *sig, char *param[]);
+
 int register_edbus_signal_handler(const char *path, const char *interface,
                const char *name, E_DBus_Signal_Cb cb);
 E_DBus_Interface *get_edbus_interface(const char *path);
index 6e40b48..2f9c55b 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "file-helper.h"
 #include "trace.h"
 #include "macro.h"
 
+#define BUF_MAX         (BUFSIZ)
+#define BUF_INC_SIZE    (512 * 1024)
+#define KB(bytes)       ((bytes)/1024)
+
 resourced_ret_c fwrite_str(const char *path, const char *str)
 {
        FILE *f;
@@ -48,7 +54,7 @@ resourced_ret_c fwrite_str(const char *path, const char *str)
        ret_value_errno_msg_if(ret == EOF, RESOURCED_ERROR_FAIL,
                               "Fail to write file\n");
 
-       return RESOURCED_ERROR_OK;
+       return RESOURCED_ERROR_NONE;
 }
 
 resourced_ret_c fwrite_int(const char *path, const int number)
@@ -89,7 +95,7 @@ resourced_ret_c fread_int(const char *path, u_int32_t *number)
        ret_value_errno_msg_if(ret == EOF, RESOURCED_ERROR_FAIL,
                               "Fail to read file\n");
 
-       return RESOURCED_ERROR_OK;
+       return RESOURCED_ERROR_NONE;
 }
 
 resourced_ret_c fwrite_array(const char *path, const void *array,
@@ -112,5 +118,68 @@ resourced_ret_c fwrite_array(const char *path, const void *array,
        ret_value_errno_msg_if(ret != numb_of_elem, RESOURCED_ERROR_FAIL,
                               "Failed write array into %s file\n");
 
-       return RESOURCED_ERROR_OK;
+       return RESOURCED_ERROR_NONE;
+}
+
+/* reads file contents into memory */
+char* cread(const char* path)
+{
+       char*   text = NULL;
+       size_t  size = 0;
+
+       ssize_t ret;
+       char*   ptr = text;
+       size_t  cap = size;
+       int     fd  = open(path, O_RDONLY);
+
+       if (fd < 0) {
+               _E("%s open error", path);
+               return NULL;
+       }
+
+       do {
+               /* ensure we have enough space */
+               if (cap == 0) {
+                       ptr = (char*)realloc(text, size + BUF_INC_SIZE);
+                       if (ptr == NULL) {
+                               ret = -1;
+                               break;
+                       }
+
+                       text  = ptr;
+                       ptr   = text + size;
+                       cap   = BUF_INC_SIZE;
+                       size += BUF_INC_SIZE;
+               }
+               ret = read(fd, ptr, cap);
+               if (ret == 0) {
+                       *ptr = 0;
+               } else if (ret > 0) {
+                       cap -= ret;
+                       ptr += ret;
+               }
+       } while (ret > 0);
+       close(fd);
+
+       return (ret < 0 ? NULL : text);
+}
+
+/* like fgets/gets but adjusting contents pointer */
+char* cgets(char** contents)
+{
+       if (contents && *contents && **contents) {
+               char* bos = *contents;          /* begin of string */
+               char* eos = strchr(bos, '\n');  /* end of string   */
+
+               if (eos) {
+                       *contents = eos + 1;
+                       *eos      = 0;
+               } else {
+                       *contents = NULL;
+               }
+
+               return bos;
+       }
+
+       return NULL;
 }
index 6930a7c..cbee9e3 100644 (file)
@@ -45,4 +45,6 @@ resourced_ret_c fwrite_array(const char *path, const void *array,
                             const size_t size_of_elem,
                             const size_t numb_of_elem);
 
+char *cread(const char *path);
+char *cgets(char **contents);
 #endif  /*_RESOURCED_FILE_HELPER_H_*/
diff --git a/src/common/genl.h b/src/common/genl.h
new file mode 100644 (file)
index 0000000..2511733
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  genl.h
+ *
+ *  Samsung Traffic Counter Module
+ *
+ *  Copyright (C) 2012 Samsung Electronics
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *   @brief Trace macro definitions.
+ *
+ */
+
+#ifndef _KERNEL_MODULE_TRAFFIC_STAT_GEN_NETLINK_H_
+#define _KERNEL_MODULE_TRAFFIC_STAT_GEN_NETLINK_H_
+
+/* attributes*/
+enum {
+       TRAF_STAT_A_UNSPEC,
+       TRAF_STAT_A_MSG,
+       TRAF_STAT_DATA_IN,
+       TRAF_STAT_DATA_OUT,
+       TRAF_STAT_COUNT,
+       TRAF_STAT_DATA_RESTRICTION,
+       __TRAF_STAT_A_MAX,
+};
+
+/*
+ * commands: enumeration of all commands (functions),
+ * used by userspace application to identify command to be executed
+ */
+enum {
+       TRAF_STAT_C_UNSPEC,
+       TRAF_STAT_C_START,
+       TRAF_STAT_C_GET_PID_OUT,
+       TRAF_STAT_C_GET_CONN_IN,
+       TRAF_STAT_C_STOP,
+       TRAF_STAT_C_SET_RESTRICTIONS,
+       __TRAF_STAT_C_MAX,
+};
+
+enum {
+       RESTRICTION_NOTI_A_UNSPEC,
+       RESTRICTION_A_CLASSID,
+       RESTRICTION_A_IFINDEX,
+       __RESTRICTION_NOTI_A_MAX,
+};
+
+enum {
+       RESTRICTION_NOTI_C_UNSPEC,
+       RESTRICTION_NOTI_C_ACTIVE,
+       RESTRICTION_NOTI_C_WARNING,
+       __RESTRICTION_NOTI_C_MAX,
+};
+
+enum {
+        NET_ACTIVITY_A_UNSPEC,
+        NET_ACTIVITY_A_DATA_IN,
+        NET_ACTIVITY_A_DATA_OUT,
+        __NET_ACTIVITY_A_MAX,
+};
+
+enum {
+        NET_ACTIVITY_C_UNSPEC,
+        NET_ACTIVITY_C_START,
+        NET_ACTIVITY_C_STOP,
+        __NET_ACTIVITY_C_MAX,
+};
+
+#endif /*_KERNEL_MODULE_TRAFFIC_STAT_GEN_NETLINK_H_ */
diff --git a/src/common/logging-common.h b/src/common/logging-common.h
new file mode 100644 (file)
index 0000000..9923896
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @file logging-common.h
+ * @desc logging common process
+ **/
+
+#ifndef __LOGGING_COMMON_H__
+#define __LOGGING_COMMON_H__
+
+enum logging_control_type {
+       LOGGING_INSERT_PROC_LIST,
+       LOGGING_UPDATE_PROC_INFO,
+       LOGGING_UPDATE_STATE
+};
+
+struct logging_data_type {
+       enum logging_control_type control_type;
+       unsigned long *args;
+};
+
+#ifdef LOGGING_SUPPORT
+int logging_control(enum logging_control_type type, unsigned long *args);
+#else
+static inline int logging_control(enum logging_control_type type, unsigned long *args)
+{
+       return RESOURCED_ERROR_NONE;
+}
+#endif /* LOGGING_SUPPORT */
+
+#endif /* __LOGGING_COMMON_H__ */
index aca2e63..caaa7a6 100644 (file)
@@ -35,6 +35,13 @@ struct lowmem_data_type {
        unsigned long *args;
 };
 
-int lowmem_control(enum lowmem_control_type type, unsigned long *args);
+#ifdef MEMORY_SUPPORT
+extern int lowmem_control(enum lowmem_control_type type, unsigned long *args);
+#else
+static inline int lowmem_control(enum lowmem_control_type type, unsigned long *args)
+{
+       return RESOURCED_ERROR_NONE;
+}
+#endif /* MEMORY_SUPPORT */
 
 #endif /* __LOWMEM_COMMON_H__ */
index 886071c..f47111c 100644 (file)
@@ -1,5 +1,31 @@
-#ifndef _PERF_CONTROL_MACRO_H
-#define _PERF_CONTROL_MACRO_H
+/*
+ * 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: macro.h
+ *
+ *  @desc general macros
+ */
+
+
+#ifndef _RESOURCED_MACRO_H_
+#define _RESOURCED_MACRO_H_
 
 #define execute_once \
        static int __func__##guardian;                                   \
@@ -11,6 +37,8 @@
 #include <stdio.h>
 #include <config.h>
 
+#define API __attribute__((visibility("default")))
+
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
 #define DECLARE_WRAPPER(fn_name, inner_fn) \
@@ -40,6 +68,13 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
        sizeof(type) <= 8 ? 20 : \
        sizeof(int[-2*(sizeof(type) > 8)])))
 
+#define ret_msg_if(expr, fmt, arg...) do { \
+        if (expr) { \
+               _E(fmt, ##arg);                 \
+                return; \
+        } \
+} while (0)
+
 #define ret_value_if(expr, val) do { \
         if (expr) { \
                 _E("(%s) -> %s():%d return", #expr, __FUNCTION__, __LINE__); \
@@ -102,6 +137,14 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
 #define gslist_for_each_item(item, list)                       \
        for(item = list; item != NULL; item = g_slist_next(item))
 
+#define gslist_for_each(head, elem, node)      \
+       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; \
+                       elem && ((node = elem->data) != NULL); \
+                       elem = elem_next, elem_next = g_list_next(elem), node = NULL)
+
 #define DB_ACTION(command) do {                                \
        if ((command) != SQLITE_OK) {                   \
                error_code = RESOURCED_ERROR_DB_FAILED; \
@@ -119,4 +162,4 @@ static void fn_name(void *data, void __attribute__((__unused__)) *not_used) \
                remove_module(module);                                  \
        }
 
-#endif /* _PERF_CONTROL_MACRO_H */
+#endif /* _RESOURCED_MACRO_H_ */
index 83ded53..ce81e5f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * resourced
  *
- * Copyright (c) 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.
 #include "module-data.h"
 #include "trace.h"
 
+static struct shared_modules_data modules_data;
+
+struct shared_modules_data *get_shared_modules_data(void)
+{
+       return &modules_data;
+}
+
 void init_modules_arg(struct modules_arg *marg, struct daemon_arg *darg)
 {
-       ret_value_msg_if(marg == NULL || darg == NULL, ,
+       ret_msg_if(marg == NULL || darg == NULL,
                         "Init modules argument failed\n");
        marg->opts = darg->opts;
 }
index 570e7bc..37f8e9b 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef __MODULE_DATA_HANDLE_H__
 #define __MODULE_DATA_HANDLE_H__
 
+#include "counter.h"
+#include "daemon-options.h"
 #include "init.h"
 #include "proc-main.h"
 
@@ -32,6 +34,17 @@ struct modules_arg {
        struct daemon_opts *opts;
 };
 
+struct swap_module_data {
+       int swaptype;                   /* swap */
+};
+
+struct shared_modules_data {
+       struct counter_arg *carg;
+       struct swap_module_data swap_data;
+};
+
+struct shared_modules_data *get_shared_modules_data(void);
+
 void init_modules_arg(struct modules_arg *marg, struct daemon_arg *darg);
 
 #endif /* __MODULE_DATA_HANDLE_H__ */
index eb7e08d..33734bb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * resourced
  *
- * Copyright (c) 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.
 
 static GSList *modules_list;
 
-void add_module(struct module_ops *module)
+void add_module(const struct module_ops *module)
 {
-       ret_value_msg_if(!module, , "Invalid module handler\n");
+       ret_msg_if(!module, "Invalid module handler\n");
        if (module->priority == MODULE_PRIORITY_HIGH)
-               modules_list = g_slist_prepend(modules_list, module);
+               modules_list = g_slist_prepend(modules_list, (gpointer)module);
        else
-               modules_list = g_slist_append(modules_list, module);
+               modules_list = g_slist_append(modules_list, (gpointer)module);
 }
 
-void remove_module(struct module_ops *module)
+void remove_module(const struct module_ops *module)
 {
-       modules_list = g_slist_remove(modules_list, module);
+       modules_list = g_slist_remove(modules_list, (gpointer)module);
 }
 
 const struct module_ops *find_module(const char *name)
@@ -58,10 +58,32 @@ const struct module_ops *find_module(const char *name)
        return NULL;
 }
 
+void modules_check_runtime_support(void *data)
+{
+       GSList *iter;
+       const struct module_ops *module;
+       int ret_code = RESOURCED_ERROR_NONE;
+
+       gslist_for_each_item(iter, modules_list) {
+               module = (const struct module_ops *)iter->data;
+               _D("check runtime support [%s] module\n", module->name);
+
+               if (!module->check_runtime_support)
+                       continue;
+
+               ret_code = module->check_runtime_support((void *)module);
+               if (ret_code != RESOURCED_ERROR_NONE) {
+                       _E("%s module check failed", module->name);
+                       remove_module(module);
+                       continue;
+               }
+       }
+}
+
 void modules_init(void *data)
 {
        GSList *iter;
-       struct module_ops *module;
+       const struct module_ops *module;
        int ret_code = RESOURCED_ERROR_NONE;
 
        gslist_for_each_item(iter, modules_list) {
@@ -79,7 +101,7 @@ void modules_exit(void *data)
        GSList *iter;
        /* Deinitialize in reverse order */
        GSList *reverse_list = g_slist_reverse(modules_list);
-       struct module_ops *module;
+       const struct module_ops *module;
        int ret_code = RESOURCED_ERROR_NONE;
 
        gslist_for_each_item(iter, reverse_list) {
index 4135134..7387cd5 100644 (file)
@@ -35,13 +35,15 @@ struct module_ops {
        const char *name;
        int (*init) (void *data);
        int (*exit) (void *data);
+       int (*check_runtime_support) (void *data);
        int (*control) (void *data);
        int (*status) (void *data);
 };
 
-void add_module(struct module_ops *module);
-void remove_module(struct module_ops *module);
+void add_module(const struct module_ops *module);
+void remove_module(const struct module_ops *module);
 
+void modules_check_runtime_support(void *data);
 void modules_init(void *data);
 void modules_exit(void *data);
 
diff --git a/src/common/notifier.c b/src/common/notifier.c
new file mode 100644 (file)
index 0000000..f994d44
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ *
+*/
+
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "notifier.h"
+
+#include <resourced.h>
+#include <trace.h>
+#include <stdlib.h>
+#include <glib.h>
+
+struct resourced_notifier {
+       enum notifier_type status;
+       int (*func)(void *data);
+};
+
+static GSList *resourced_notifier_list;
+
+#define FIND_NOTIFIER(a, b, d, e, f) \
+       gslist_for_each(a, b, d) \
+               if (e == d->e && f == (d->f))
+
+int register_notifier(enum notifier_type status, int (*func)(void *data))
+{
+       GSList *n;
+       struct resourced_notifier *notifier;
+
+       _I("%d, %x", status, func);
+
+       if (!func) {
+               _E("invalid func address!");
+               return -EINVAL;
+       }
+
+       FIND_NOTIFIER(resourced_notifier_list, n, notifier, status, func) {
+               _E("function is already registered! [%d, %x]",
+                   status, func);
+               return -EINVAL;
+       }
+
+       notifier = malloc(sizeof(struct resourced_notifier));
+       if (!notifier) {
+               _E("Fail to malloc for notifier!");
+               return -ENOMEM;
+       }
+
+       notifier->status = status;
+       notifier->func = func;
+
+       resourced_notifier_list = g_slist_append(resourced_notifier_list, notifier);
+
+       return 0;
+}
+
+int unregister_notifier(enum notifier_type status, int (*func)(void *data))
+{
+       GSList *n;
+       struct resourced_notifier *notifier;
+
+       if (!func) {
+               _E("invalid func address!");
+               return -EINVAL;
+       }
+
+       FIND_NOTIFIER(resourced_notifier_list, n, notifier, status, func) {
+               _I("[%d, %x]", status, func);
+               resourced_notifier_list = g_slist_remove(resourced_notifier_list, notifier);
+               free(notifier);
+       }
+
+       return 0;
+}
+
+void resourced_notify(enum notifier_type status, void *data)
+{
+       GSList *iter;
+       struct resourced_notifier *notifier;
+
+       gslist_for_each_item(iter, resourced_notifier_list) {
+               notifier = (struct resourced_notifier *)iter->data;
+               if (status == notifier->status) {
+                       if (notifier->func)
+                               notifier->func(data);
+               }
+       }
+}
+
+static int notifier_exit(void *data)
+{
+       GSList *iter;
+       /* Deinitialize in reverse order */
+       GSList *reverse_list = g_slist_reverse(resourced_notifier_list);
+       struct resourced_notifier *notifier;
+
+       gslist_for_each_item(iter, reverse_list) {
+               notifier = (struct resourced_notifier *)iter->data;
+               resourced_notifier_list = g_slist_remove(resourced_notifier_list, iter);
+               free(notifier);
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops notifier_ops = {
+       .priority = MODULE_PRIORITY_NORMAL,
+       .name     = "notifier",
+       .exit     = notifier_exit,
+};
+
+MODULE_REGISTER(&notifier_ops)
+
diff --git a/src/common/notifier.h b/src/common/notifier.h
new file mode 100644 (file)
index 0000000..46f112a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ */
+
+
+#ifndef __NOTIFIER_H__
+#define __NOTIFIER_H__
+
+enum notifier_type {
+       RESOURCED_NOTIFIER_APP_LAUNCH,
+       RESOURCED_NOTIFIER_APP_RESUME,
+       RESOURCED_NOTIFIER_APP_FOREGRD,
+       RESOURCED_NOTIFIER_APP_BACKGRD,
+       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_MAX,
+};
+
+/*
+ * This is for internal callback method.
+ */
+int register_notifier(enum notifier_type status, int (*func)(void *data));
+int unregister_notifier(enum notifier_type status, int (*func)(void *data));
+void resourced_notify(enum notifier_type status, void *value);
+
+#endif /* __NOTIFIER_H__ */
diff --git a/src/common/swap-common.h b/src/common/swap-common.h
new file mode 100644 (file)
index 0000000..7760e5c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @file swap-common.h
+ * @desc swap common process
+ **/
+
+#ifndef __SWAP_COMMON_H__
+#define __SWAP_COMMON_H__
+
+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);
+#else
+static inline int swap_status(enum swap_status_type type, unsigned long *args)
+{
+       return RESOURCED_ERROR_NONE;
+}
+#endif /* SWAP_SUPPORT */
+
+#endif /* __SWAP_COMMON_H__ */
index 049ff9a..bd56dff 100644 (file)
@@ -26,7 +26,7 @@
 #ifndef _SYSTEM_RESOURCE_TRACE_H_
 #define _SYSTEM_RESOURCE_TRACE_H_
 
-#include <config.h>
+#include "config.h"
 #include <dlog.h>
 #include <errno.h>
 #include <signal.h>
diff --git a/src/common/transmission.h b/src/common/transmission.h
new file mode 100644 (file)
index 0000000..48c8fa9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * @file transmission.h
+ * @brief Kernel - user space transmition structures
+ *
+ */
+
+#ifndef _TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION_H_
+#define _TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION_H_
+#ifdef _KERNEL_
+#include <linux/socket.h>
+#include <linux/types.h>
+#else
+#include <netinet/in.h>
+#include <sys/types.h>
+#endif
+
+/* Used both in kernel module and in control daemon */
+
+/*
+ * @brief Entity for outgoing and incomming packet counter information.
+ * Used for serialization.
+ */
+struct traffic_event {
+       u_int32_t sk_classid;
+       unsigned long bytes;
+       int ifindex;
+};
+
+enum traffic_restriction_type {
+       RST_UNDEFINDED,
+       RST_SET,
+       RST_UNSET,
+       RST_EXCLUDE,
+       RST_MAX_VALUE
+};
+
+/*
+ * @brief Traffic restriction structure for serialization
+ * type - traffic_restriction_type
+ */
+struct traffic_restriction {
+       u_int32_t sk_classid;
+       int type;
+       int ifindex;
+       int send_limit;
+       int rcv_limit;
+       int snd_warning_threshold;
+       int rcv_warning_threshold;
+};
+
+#define RESOURCED_ALL_IFINDEX 1
+
+#endif                         /*TRAFFIC_CONTROL_TRAFFIC_STAT_TRANSMITION */
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
new file mode 100644 (file)
index 0000000..db677ea
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file cpu.c
+ *
+ * @desc cpu module
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+#include <dirent.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "notifier.h"
+#include "proc-main.h"
+#include "proc-process.h"
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "resourced.h"
+#include "trace.h"
+#include "vconf.h"
+#include "cgroup.h"
+#include "config-parser.h"
+#include "const.h"
+
+#define CPU_DEFAULT_CGROUP "/sys/fs/cgroup/cpu"
+#define CPU_CONTROL_GROUP "/sys/fs/cgroup/cpu/background"
+#define CPU_CONTROL_SERVICE_GROUP "/sys/fs/cgroup/cpu/service"
+#define CPU_CONF_FILE                  "/etc/resourced/cpu.conf"
+#define CPU_CONF_SECTION       "CONTROL"
+#define CPU_CONF_PREDEFINE     "PREDEFINE"
+#define CPU_SHARE      "/cpu.shares"
+
+static int cpu_move_cgroup(pid_t pid, char *path)
+{
+       return cgroup_write_node(path, CGROUP_FILE_NAME, pid);
+}
+
+static int load_cpu_config(struct parse_result *result, void *user_data)
+{
+       pid_t pid = 0, value;
+       if (!result)
+               return -EINVAL;
+
+       if (strcmp(result->section, CPU_CONF_SECTION))
+               return RESOURCED_ERROR_NO_DATA;
+       if (!strcmp(result->name, CPU_CONF_PREDEFINE)) {
+               pid = find_pid_from_cmdline(result->value);
+               if (pid > 0)
+                       cpu_move_cgroup(pid, CPU_CONTROL_GROUP);
+       } else if (!strcmp(result->name, "BACKGROUND_CPU_SHARE")) {
+               value = atoi(result->value);
+               if (value)
+                       cgroup_write_node(CPU_CONTROL_GROUP, CPU_SHARE, value);
+       } else if (!strcmp(result->name, "SERVICE_CPU_SHARE")) {
+               value = atoi(result->value);
+               if (value)
+                       cgroup_write_node(CPU_CONTROL_SERVICE_GROUP, CPU_SHARE, value);
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static int cpu_service_launch(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       _D("cpu_service_launch : pid = %d, appname = %s", p_data->pid, p_data->appid);
+       cpu_move_cgroup(p_data->pid, CPU_CONTROL_SERVICE_GROUP);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int cpu_foreground_state(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       _D("cpu_foreground_state : pid = %d, appname = %s", p_data->pid, p_data->appid);
+       cpu_move_cgroup(p_data->pid, CPU_DEFAULT_CGROUP);
+       return RESOURCED_ERROR_NONE;
+}
+
+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);
+       cpu_move_cgroup(p_data->pid, CPU_CONTROL_SERVICE_GROUP);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_cpu_init(void *data)
+{
+       int ret_code;
+
+       _D("resourced_cpu_init");
+       ret_code = make_cgroup_subdir(CPU_DEFAULT_CGROUP, "background", NULL);
+       ret_value_msg_if(ret_code < 0, ret_code, "cpu init failed\n");
+       ret_code = make_cgroup_subdir(CPU_DEFAULT_CGROUP, "service", NULL);
+       ret_value_msg_if(ret_code < 0, ret_code, "create service cgroup failed\n");
+       config_parse(CPU_CONF_FILE, load_cpu_config, 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);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_cpu_finalize(void *data)
+{
+       unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, cpu_service_launch);
+       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);
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops cpu_modules_ops = {
+       .priority = MODULE_PRIORITY_NORMAL,
+       .name = "cpu",
+       .init = resourced_cpu_init,
+       .exit = resourced_cpu_finalize,
+};
+
+MODULE_REGISTER(&cpu_modules_ops)
diff --git a/src/cpu/cpu.conf b/src/cpu/cpu.conf
new file mode 100644 (file)
index 0000000..609c464
--- /dev/null
@@ -0,0 +1,6 @@
+[CONTROL]
+# predefined process list
+PREDEFINE=indicator
+PREDEFINE=net-config
+BACKGROUND_CPU_SHARE=50
+SERVICE_CPU_SHARE=128
diff --git a/src/cpu/logging-cpu.c b/src/cpu/logging-cpu.c
new file mode 100644 (file)
index 0000000..bdb7c1a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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 logging-cpu.c
+ *
+ * @desc start cpu logging system for resourced
+ *
+ * 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 <systemd/sd-journal.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "module.h"
+#include "macro.h"
+#include "proc-process.h"
+#include "logging.h"
+
+#define        PROC_STAT_PATH "/proc/%d/stat"
+#define        CPU_NAME "cpu"
+#define        CPU_COMMIT_INTERVAL             30*60   /* 20 min */
+
+#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_BACKGRD_INTERVAL            10*60   /* 2 min */
+#define        CPU_BACKGRD_OLD_INTERVAL        15*60   /* 5 min */
+
+struct logging_cpu_info {
+       unsigned long utime;
+       unsigned long stime;
+       unsigned long last_utime;
+       unsigned long last_stime;
+       bool last_commited;
+       time_t last_log_time;
+       time_t log_interval;
+       pid_t last_pid;
+};
+
+static int get_cpu_time(pid_t pid, unsigned long *utime,
+       unsigned long *stime)
+{
+       char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
+       FILE *fp;
+
+       assert(utime != NULL);
+       assert(stime != NULL);
+
+       sprintf(proc_path, PROC_STAT_PATH, pid);
+       fp = fopen(proc_path, "r");
+       if (fp == NULL)
+               return RESOURCED_ERROR_FAIL;
+
+       if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
+               fclose(fp);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
+               fclose(fp);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       fclose(fp);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void update_log_interval(struct logging_cpu_info *loginfo, int oom,
+       int always)
+{
+       if (!always && (oom < OOMADJ_FOREGRD_LOCKED))
+               return;
+
+       switch (oom) {
+       case OOMADJ_DISABLE:
+       case OOMADJ_SERVICE_MIN:
+       case OOMADJ_SU:
+               loginfo->log_interval = CPU_MAX_INTERVAL;
+               break;
+       case OOMADJ_INIT:
+               loginfo->log_interval = CPU_INIT_INTERVAL;
+               break;
+       case OOMADJ_FOREGRD_LOCKED:
+       case OOMADJ_FOREGRD_UNLOCKED:
+       case OOMADJ_BACKGRD_LOCKED:
+       case OOMADJ_SERVICE_DEFAULT:
+       case OOMADJ_SERVICE_FOREGRD:
+               loginfo->log_interval = CPU_FOREGRD_INTERVAL;
+               break;
+       case OOMADJ_BACKGRD_UNLOCKED:
+       case OOMADJ_SERVICE_BACKGRD:
+               loginfo->log_interval = CPU_BACKGRD_INTERVAL;
+               break;
+       default:
+               if (oom > OOMADJ_BACKGRD_UNLOCKED)
+                       loginfo->log_interval = CPU_BACKGRD_OLD_INTERVAL;
+               break;
+       }
+}
+
+static int init_cpu_info(void **pl, int pid, int oom, time_t now)
+{
+       struct logging_cpu_info *info;
+
+       info = (struct logging_cpu_info *)
+                       malloc(sizeof(struct logging_cpu_info));
+       if (!info) {
+               _E("malloc for logging_cpu_info is failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+       info->last_pid = pid;
+       info->utime = 0;
+       info->stime = 0;
+       info->last_utime = 0;
+       info->last_stime = 0;
+       info->last_log_time = now;
+       info->last_commited = false;
+
+       update_log_interval(info, oom, 1);
+       *pl = (void *)info;
+       return RESOURCED_ERROR_NONE;
+}
+
+/* pss_interval should be adjusted depending on app type */
+static int update_cpu_info(void *pl, pid_t pid, int oom,
+       time_t now, unsigned always)
+{
+       int ret = RESOURCED_ERROR_NONE;
+       struct logging_cpu_info *loginfo = (struct logging_cpu_info *)pl;
+       unsigned long utime = 0, stime = 0;
+       unsigned long utime_diff = 0, stime_diff = 0;
+
+       if (!always) {
+               unsigned long update_interval = now - loginfo->last_log_time;
+               if (update_interval < CPU_MAX_INTERVAL) {
+                       if (now < loginfo->last_log_time + loginfo->log_interval)
+                               return ret;
+               } else {
+                       loginfo->last_log_time = now;
+               }
+       }
+
+       ret = get_cpu_time(pid, &utime, &stime);
+
+       if (ret != RESOURCED_ERROR_NONE)
+               return ret;
+
+       if (loginfo->last_pid == pid) {
+               if (loginfo->last_utime > utime)
+                       goto out;
+
+               utime_diff = utime - loginfo->last_utime;
+               loginfo->last_utime = utime;
+               loginfo->utime += utime_diff;
+               if (loginfo->stime > stime)
+                       goto out;
+               stime_diff = stime - loginfo->last_stime;
+               loginfo->last_stime = stime;
+               loginfo->stime += stime_diff;
+
+       } else {
+               loginfo->last_pid = pid;
+               loginfo->utime += utime;
+               loginfo->stime += stime;
+               loginfo->last_utime = utime;
+               loginfo->last_stime = stime;
+       }
+
+out:
+       loginfo->last_log_time = now;
+       loginfo->last_commited = false;
+       update_log_interval(loginfo, oom, 0);
+       return ret;
+}
+
+static int write_cpu_info(char *name, struct logging_infos *infos,
+       int ss_index)
+{
+       struct logging_cpu_info *ci = infos->stats[ss_index];
+
+       if (!infos->running && ci->last_commited)
+               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_commited = true;
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct logging_info_ops cpu_info_ops = {
+       .update = update_cpu_info,
+       .write  = write_cpu_info,
+       .init   = init_cpu_info,
+};
+
+static int logging_cpu_init(void *data)
+{
+       int ret;
+
+       ret = register_logging_subsystem(CPU_NAME, &cpu_info_ops);
+       if(ret != RESOURCED_ERROR_NONE) {
+               _E("register logging subsystem failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+       ret = update_commit_interval(CPU_NAME, CPU_COMMIT_INTERVAL);
+       if(ret != RESOURCED_ERROR_NONE) {
+               _E("update commit interval logging subsystem failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       _D("logging cpu init finished");
+       return RESOURCED_ERROR_NONE;
+}
+
+static int logging_cpu_exit(void *data)
+{
+       _D("logging cpu exit");
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops logging_cpu_ops = {
+       .priority       = MODULE_PRIORITY_NORMAL,
+       .name           = "logging_cpu",
+       .init           = logging_cpu_init,
+       .exit           = logging_cpu_exit,
+};
+
+MODULE_REGISTER(&logging_cpu_ops)
diff --git a/src/logging/include/logging.h b/src/logging/include/logging.h
new file mode 100644 (file)
index 0000000..e64a223
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @file logging.h
+ * @desc define structures and functions for logging.
+ **/
+
+#ifndef __LOGGING_H__
+#define __LOGGING_H__
+
+#define        SS_NAME_MAX 10
+
+struct logging_infos {
+       pid_t pid;
+       int oom;
+       void **stats;
+       bool running;
+};
+
+struct logging_info_ops {
+       int (*update)(void *, pid_t, int, time_t, unsigned);
+       int (*write)(char *, struct logging_infos *, int);
+       int (*init)(void **, pid_t, int, time_t);
+};
+
+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
new file mode 100644 (file)
index 0000000..fd81f1c
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * resourced
+ *
+ * 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.
+ * 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 logging.c
+ *
+ * @desc start logging system for resourced
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <Ecore.h>
+
+#include "trace.h"
+#include "logging-common.h"
+#include "resourced.h"
+#include "macro.h"
+#include "module.h"
+#include "proc-process.h"
+#include "proc-main.h"
+#include "proc_stat.h"
+#include "logging.h"
+#include "edbus-handler.h"
+
+#define        BUF_MAX                 1024
+#define        WRITE_INFO_MAX          10
+#define        MAX_PROC_LIST           200
+
+#define        WEBPROCESS_NAME         "WebProcess"
+#define        MAX_PROC_ITEM           200
+#define        INC_PROC_ITEM           10
+#define        COMMIT_INTERVAL         10*60   /* 10 min */
+#define LOGGING_PTIORITY       -20
+
+#define SIGNAL_LOGGING_INIT    "LoggingInit"
+#define SIGNAL_LOGGING_GET     "LoggingGet"
+#define SIGNAL_LOGGING_UPDATED "LoggingUpdated"
+#define PROC_OOM_SCORE_ADJ_PATH        "/proc/%d/oom_score_adj"
+
+struct logging_sub_sys {
+       const char *name;
+       time_t commit_interval;
+       time_t last_commit;
+       struct logging_info_ops *ops;
+};
+
+static const struct module_ops logging_modules_ops;
+static const struct module_ops *logging_ops;
+
+static int num_log_infos;
+static bool need_to_update;
+static GHashTable *logging_proc_list;
+static GArray *logging_ss_list;
+static pthread_t       logging_thread  = 0;
+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 int init_logging_infos(struct logging_infos *info, const char *key,
+       pid_t pid, int oom, time_t now)
+{
+       int i;
+       int ret;
+
+       if (!info) {
+               _D("info is null");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       info->oom = oom;
+       info->pid = pid;
+       info->running = true;
+
+       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 = ss->ops->init(&(info->stats[i]), pid, oom, now);
+               if (ret != RESOURCED_ERROR_NONE) {
+                       _E("init logging at %lu", now);
+                       /* not return error, just continue updating */
+               }
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void update_logging_infos(struct logging_infos *info,
+       time_t now, unsigned first)
+{
+       int i;
+       int ret;
+       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 = ss->ops->update(info->stats[i], info->pid, info->oom, now, first);
+               if (ret != RESOURCED_ERROR_NONE) {
+                       /*
+                        * when update failed, this is because there is no
+                        * running process. So, just update processes running
+                        * state.
+                        */
+                       info->running = false;
+               }
+       }
+
+       return;
+}
+
+static void insert_hash_table(char *key, pid_t pid, int oom)
+{
+       struct logging_infos *info;
+       void **stats;
+       char *name;
+       time_t now;
+
+       now = time(NULL);
+
+       name = malloc(strlen(key) + 1);
+
+       if (!name) {
+               _D("memory allocation for name failed");
+               return;
+       }
+       strcpy(name, key);
+       info = (struct logging_infos *)malloc(sizeof(struct logging_infos));
+
+       if (!info) {
+               _D("memory allocation for logging_infos failed");
+               free(name);
+               return;
+       }
+
+       stats = (void **)malloc(sizeof(void *) * num_log_infos);
+
+       if (!stats) {
+               _D("memory allocation for log infos fails");
+               free(name);
+               free(info);
+               return;
+       }
+
+       info->stats = stats;
+       init_logging_infos(info, name, pid, oom, now);
+
+       g_hash_table_insert(logging_proc_list, (gpointer) name, (gpointer) info);
+       update_logging_infos(info, now, true);
+       return;
+}
+
+static int write_journal(struct logging_sub_sys *pss, int ss_index)
+{
+       gpointer value;
+       gpointer key;
+       int ret = RESOURCED_ERROR_NONE;
+       char *name;
+       GHashTableIter iter;
+       struct logging_infos *infos;
+       g_hash_table_iter_init(&iter, logging_proc_list);
+
+       while (1) {
+               ret = pthread_mutex_lock(&proc_list_mutex);
+               if (ret) {
+                       _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
+                       return ret;
+               }
+
+               if (!g_hash_table_iter_next(&iter, &key, &value)) {
+                       ret = pthread_mutex_unlock(&proc_list_mutex);
+                       if (ret) {
+                               _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+                               return ret;
+                       }
+                       break;
+               }
+
+               name = (char *)key;
+               infos = (struct logging_infos *)value;
+               pss->ops->write(name, infos, ss_index);
+               ret = pthread_mutex_unlock(&proc_list_mutex);
+               if (ret) {
+                       _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+                       return ret;
+               }
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int write_logging_subsys_info(struct logging_sub_sys *pss, int sindex,
+       time_t now, bool force)
+{
+
+       if (!force && now < pss->last_commit + pss->commit_interval)
+               return RESOURCED_ERROR_NONE;
+
+       _D("start write %s subsys, now %lu, last:%lu, interval:%lu",
+               pss->name, now, pss->last_commit, pss->commit_interval);
+
+       write_journal(pss, sindex);
+
+       pss->last_commit = now;
+       return RESOURCED_ERROR_NONE;
+
+}
+
+static int write_logging_infos(bool force)
+{
+       int i;
+       int ret;
+       time_t now;
+
+       now = time(NULL);
+
+       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);
+               if (ret != RESOURCED_ERROR_NONE) {
+                       _E("write logging at %lu", now);
+                       /* not return error, just continue updating */
+               }
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+int register_logging_subsystem(const char*name, struct logging_info_ops *ops)
+{
+       struct logging_sub_sys ss;
+       char *ss_name;
+       time_t now;
+
+       ss_name = malloc(strlen(name)+1);
+
+       if (!ss_name) {
+               _E("memory allocation for name is failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       now = time(NULL);
+
+       strcpy(ss_name, name);
+       ss.name = ss_name;
+       ss.commit_interval = COMMIT_INTERVAL;
+       ss.last_commit = now;
+       ss.ops = ops;
+
+       g_array_append_val(logging_ss_list, ss);
+       num_log_infos++;
+
+       return RESOURCED_ERROR_NONE;
+}
+
+int update_commit_interval(const char *name, time_t commit_interval)
+{
+       int i;
+       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);
+               if (!strcmp(ss->name, name)) {
+                       ss->commit_interval = commit_interval;
+                       _D("%s logging subsystem commit interval updated to %lu",
+                       ss->name, ss->commit_interval);
+                       return RESOURCED_ERROR_NONE;
+               }
+       }
+
+       _D("%s subsystem update fail, not exist", name);
+       return RESOURCED_ERROR_FAIL;
+}
+
+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;
+}
+
+static int get_cmdline(pid_t pid, char *cmdline)
+{
+       char buf[PROC_BUF_MAX];
+       FILE *fp;
+
+       sprintf(buf, "/proc/%d/cmdline", pid);
+       fp = fopen(buf, "r");
+       if (fp == NULL)
+               return RESOURCED_ERROR_FAIL;
+
+       if (fgets(cmdline, PROC_NAME_MAX-1, fp) == NULL) {
+               fclose(fp);
+               return RESOURCED_ERROR_FAIL;
+       }
+       fclose(fp);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void insert_proc_list(pid_t pid, pid_t pgid, int oom)
+{
+       int ret = RESOURCED_ERROR_NONE;
+       char name[PROC_NAME_MAX];
+       struct logging_infos *info;
+
+       ret = get_cmdline(pid, name);
+       /*
+        * if cmdline does not exist, remove item from queue
+        * and continue logging remaining items
+        */
+       if (ret != RESOURCED_ERROR_NONE) {
+               return;
+       }
+
+       if (is_webprocess(name)) {
+               ret = rename_webprocess(pgid, name);
+               if (ret != RESOURCED_ERROR_NONE)
+                       return;
+
+       }
+
+       ret = pthread_mutex_lock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
+               return;
+       }
+
+       info = (struct logging_infos *)
+               g_hash_table_lookup(logging_proc_list, name);
+
+       /* To Do: handle multiple daemons with the same name */
+       if (!info) {
+               insert_hash_table(name, pid, oom);
+       } else {
+               info->running = true;
+               info->pid = pid;
+               info->oom = oom;
+       }
+
+       ret = pthread_mutex_unlock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+               return;
+       }
+       return;
+}
+
+static bool is_running_process(GArray *garray, pid_t pid)
+{
+       int i;
+       pid_t tpid;
+
+       for (i = 0 ; i < garray->len; i++) {
+               tpid = g_array_index(garray, pid_t, i);
+               if (tpid == pid)
+                       return true;
+       }
+       return false;
+}
+
+static void update_proc_state(void)
+{
+       DIR *dirp;
+       struct dirent *entry;
+       GArray *running_procs = NULL;
+       GHashTableIter iter;
+       int ret;
+       gpointer key, value;
+
+       running_procs = g_array_new(false, false, sizeof(pid_t));
+
+       if (!running_procs) {
+               _E("fail to create garray for pids");
+               return;
+       }
+
+       dirp = opendir("/proc");
+
+       if (dirp == NULL) {
+               _E("/proc open is failed, and cannot updated running procs");
+               return;
+       }
+
+       while ((entry = readdir(dirp)) != NULL) {
+               pid_t pid;
+
+               if (!isdigit(entry->d_name[0]))
+                       continue;
+               pid = atoi(entry->d_name);
+               g_array_append_val(running_procs, pid);
+       }
+
+       closedir(dirp);
+
+       g_hash_table_iter_init(&iter, logging_proc_list);
+
+       ret = pthread_mutex_lock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
+               g_array_free(running_procs, true);
+               return;
+       }
+
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct logging_infos *info = (struct logging_infos *)value;
+               info->running = is_running_process(running_procs, info->pid);
+       }
+
+       g_array_free(running_procs, true);
+
+       ret = pthread_mutex_unlock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+               return;
+       }
+
+       need_to_update = false;
+       return;
+}
+
+static void update_proc_list(void)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+       time_t now;
+       struct logging_infos *infos;
+       int ret;
+
+       if (need_to_update)
+               update_proc_state();
+
+       now = time(NULL);
+
+       g_hash_table_iter_init(&iter, logging_proc_list);
+
+       while (1) {
+               ret = pthread_mutex_lock(&proc_list_mutex);
+               if (ret) {
+                       _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
+                       return;
+               }
+
+               if (!g_hash_table_iter_next(&iter, &key, &value)) {
+                       ret = pthread_mutex_unlock(&proc_list_mutex);
+                       if (ret) {
+                               _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+                               return;
+                       }
+                       _D("finish proc list update");
+                       break;
+               }
+               infos = (struct logging_infos *)value;
+
+               if (infos->running)
+                       update_logging_infos(infos, now, false);
+               ret = pthread_mutex_unlock(&proc_list_mutex);
+               if (ret) {
+                       _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+                       return;
+               }
+       }
+
+       return;
+}
+
+static void logging_update_state(void)
+{
+       need_to_update = true;
+}
+
+static int check_running(gpointer key, gpointer value, gpointer user_data)
+{
+       struct logging_infos *infos = (struct logging_infos *)value;
+
+       return !(infos->running);
+}
+
+static void reclaim_proc_list(void)
+{
+       int ret;
+
+       ret = pthread_mutex_lock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_lock() failed, %d", ret);
+               return;
+       }
+
+       g_hash_table_foreach_remove(logging_proc_list, check_running, NULL);
+       ret = pthread_mutex_unlock(&proc_list_mutex);
+       if (ret) {
+               _E("proc_list_mutex::pthread_mutex_unlock() failed, %d", ret);
+               return;
+       }
+}
+
+static void logging(void)
+{
+       update_proc_list();
+
+       if (g_hash_table_size(logging_proc_list) > MAX_PROC_LIST) {
+               write_logging_infos(true);
+               reclaim_proc_list();
+       } else
+               write_logging_infos(false);
+}
+
+static void *logging_pthread(void *arg)
+{
+       int ret = 0;
+
+       setpriority(PRIO_PROCESS, 0, LOGGING_PTIORITY);
+
+       while (1) {
+               /*
+                * When signalled by main thread,
+                * it starts logging_pthread().
+                */
+               ret = pthread_mutex_lock(&logging_mutex);
+               if ( ret ) {
+                       _E("logging thread::pthread_mutex_lock() failed, %d", ret);
+                       break;
+               }
+
+               ret = pthread_cond_wait(&logging_cond, &logging_mutex);
+               if ( ret ) {
+                       _E("logging thread::pthread_cond_wait() failed, %d", ret);
+                       ret = pthread_mutex_unlock(&logging_mutex);
+                       if ( ret )
+                               _E("logging thread::pthread_mutex_lock() failed, %d", ret);
+                       break;
+               }
+
+               logging();
+
+               ret = pthread_mutex_unlock(&logging_mutex);
+               if ( ret ) {
+                       _E("logging thread::pthread_mutex_unlock() failed, %d", ret);
+                       break;
+               }
+       }
+
+       /* Now our thread finishes - cleanup TID */
+       logging_thread = 0;
+
+       return NULL;
+}
+
+
+static int logging_thread_create(void)
+{
+       int ret = RESOURCED_ERROR_NONE;
+
+       if (logging_thread) {
+               _I("logging thread %u already created", (unsigned)logging_thread);
+       } else {
+               /* initialize logging_thread */
+               ret = pthread_create(&logging_thread, NULL, (void *)logging_pthread, (void *)NULL);
+               if (ret) {
+                       _E("pthread creation for logging_pthread failed, %d\n", ret);
+                       logging_thread = 0;
+               } else {
+                       _D("pthread creation for logging success");
+                       pthread_detach(logging_thread);
+               }
+       }
+
+       return ret;
+}
+
+static void free_key(gpointer key)
+{
+       if (!key)
+               free(key);
+}
+
+static void free_value(gpointer value)
+{
+       int i;
+       struct logging_infos * info = (struct logging_infos *)value;
+
+       if (!info)
+               return;
+
+       for (i = 0; i < num_log_infos; i++) {
+               if (info->stats[i])
+                       free(info->stats[i]);
+       }
+
+       if (info->stats)
+               free(info->stats);
+
+       free(info);
+}
+
+static void initialize_logging_proc_list(void)
+{
+       DIR *dirp;
+       struct dirent *entry;
+       char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
+       int cur_oom = -1;
+       FILE *fp = NULL;
+
+       dirp = opendir("/proc");
+
+       if (dirp == NULL) {
+               _E("/proc open is failed, and cannot updated running procs");
+               return;
+       }
+
+       while ((entry = readdir(dirp)) != NULL) {
+               pid_t pid, pgid;
+
+               if (!isdigit(entry->d_name[0]))
+                       continue;
+               pid = atoi(entry->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);
+               fclose(fp);
+               insert_proc_list(pid, pgid, cur_oom);
+       }
+
+       closedir(dirp);
+       write_logging_infos(true);
+       return;
+}
+
+static void logging_update_start(void)
+{
+       int ret;
+       /* signal to logging_pthread to start */
+       ret = pthread_mutex_lock(&logging_mutex);
+       if (ret) {
+               _E("logging_update_start::pthread_mutex_lock() failed, %d", ret);
+               return;
+       }
+
+       ret = pthread_cond_signal(&logging_cond);
+       if (ret) {
+               _E("logging_update_start::pthread_cond_wait() failed, %d", ret);
+               ret = pthread_mutex_unlock(&logging_mutex);
+               if ( ret )
+                       _E("logging_update_start::pthread_mutex_unlock() failed, %d", ret);
+               return;
+       }
+
+       _D("send signal logging_pthread");
+       ret = pthread_mutex_unlock(&logging_mutex);
+       if (ret) {
+               _E("logging_update_start::pthread_mutex_unlock() failed, %d", ret);
+               return;
+       }
+}
+
+static void broadcast_logging_data_updated_signal(void)
+{
+       int r;
+
+       r = broadcast_edbus_signal_str(RESOURCED_PATH_LOGGING, RESOURCED_INTERFACE_LOGGING,
+                       SIGNAL_LOGGING_UPDATED, NULL, NULL);
+       _I("broadcast logging_data updated signal!");
+
+       if (r < 0)
+               _E("Failed: broadcast logging_data_updated signal");
+}
+
+static void logging_init_booting_done_edbus_signal_handler(void *data, DBusMessage *msg)
+{
+       int ret;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_LOGGING,
+               SIGNAL_LOGGING_INIT);
+       if (ret == 0) {
+               _D("there is booting done signal");
+               return;
+       }
+       initialize_logging_proc_list();
+       _D("logging_init_booting_done_edbus_signal_handler");
+}
+
+static void logging_get_edbus_signal_handler(void *data, DBusMessage *msg)
+{
+       int ret;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_LOGGING,
+               SIGNAL_LOGGING_GET);
+       if (ret == 0) {
+               _D("there is logging get signal");
+               return;
+       }
+       write_logging_infos(true);
+       _D("logging_get_edbus_signal_handler");
+       broadcast_logging_data_updated_signal();
+}
+
+static int logging_init(void)
+{
+       int ret = RESOURCED_ERROR_NONE;
+
+       _D("logging_init start");
+
+       logging_proc_list = g_hash_table_new_full(
+               g_str_hash,
+               g_str_equal,
+               free_key,
+               free_value);
+
+       if (!logging_proc_list) {
+               _E("fail g_hash_table_new_full() for logging_proc_list");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       logging_ss_list = g_array_new(false, false,
+               sizeof(struct logging_sub_sys));
+
+       if (logging_ss_list == NULL)
+               return RESOURCED_ERROR_FAIL;
+
+       ret = logging_thread_create();
+       if (ret) {
+               _E("logging thread create failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
+               RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_INIT,
+                   (void *)logging_init_booting_done_edbus_signal_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_LOGGING,
+               RESOURCED_INTERFACE_LOGGING, SIGNAL_LOGGING_GET,
+                   (void *)logging_get_edbus_signal_handler);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_logging_control(void *data)
+{
+       int ret = RESOURCED_ERROR_NONE;
+       struct logging_data_type *l_data;
+
+       if (!num_log_infos)
+               return ret;
+
+       l_data = (struct logging_data_type *)data;
+
+       switch(l_data->control_type) {
+       case LOGGING_INSERT_PROC_LIST:
+               if (l_data->args)
+                       insert_proc_list((pid_t)l_data->args[0],
+                               (pid_t)l_data->args[1], (int)l_data->args[2]);
+               break;
+       case LOGGING_UPDATE_PROC_INFO:
+               logging_update_start();
+               break;
+       case LOGGING_UPDATE_STATE:
+               logging_update_state();
+               break;
+       }
+       return ret;
+}
+
+static int resourced_logging_init(void *data)
+{
+       logging_ops = &logging_modules_ops;
+
+       return logging_init();
+}
+
+static int resourced_logging_exit(void *data)
+{
+       if (logging_ss_list)
+               g_array_free(logging_ss_list, TRUE);
+       if (logging_proc_list)
+               g_hash_table_destroy(logging_proc_list);
+       return RESOURCED_ERROR_NONE;
+}
+
+int logging_control(enum logging_control_type type, unsigned long *args)
+{
+       struct logging_data_type l_data;
+
+       if (logging_ops) {
+               l_data.control_type = type;
+               l_data.args = args;
+               return logging_ops->control(&l_data);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static const struct module_ops logging_modules_ops = {
+       .priority       = MODULE_PRIORITY_HIGH,
+       .name           = "logging",
+       .init           = resourced_logging_init,
+       .exit           = resourced_logging_exit,
+       .control        = resourced_logging_control,
+};
+
+MODULE_REGISTER(&logging_modules_ops)
diff --git a/src/memory/logging-memory.c b/src/memory/logging-memory.c
new file mode 100644 (file)
index 0000000..532d671
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * 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 logging-memory.c
+ *
+ * @desc start memory logging system for resourced
+ *
+ * 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 <systemd/sd-journal.h>
+
+#include "resourced.h"
+#include "trace.h"
+#include "file-helper.h"
+#include "module.h"
+#include "macro.h"
+#include "proc-process.h"
+#include "logging.h"
+
+#define        MEM_NAME "memory"
+#define        MEM_COMMIT_INTERVAL             30*60   /* 30 min */
+
+#define        MEM_MAX_INTERVAL                10*60   /* 10 min */
+#define        MEM_INIT_INTERVAL               8*60    /* 8 min */
+#define MEM_FOREGRD_INTERVAL           5*60    /* 5 min */
+#define MEM_BACKGRD_INTERVAL           10*60   /* 10 min */
+#define MEM_BACKGRD_OLD_INTERVAL       15*60   /* 15 min */
+
+struct logging_memory_info {
+       unsigned avg_pss;
+       unsigned max_pss;
+       unsigned avg_uss;
+       unsigned max_uss;
+       unsigned sampling_count;
+       bool last_commited;
+       time_t last_log_time;
+       time_t log_interval;
+       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)
+{
+       if (!always && (oom < OOMADJ_FOREGRD_LOCKED))
+               return;
+
+       switch (oom) {
+       case OOMADJ_DISABLE:
+       case OOMADJ_SERVICE_MIN:
+       case OOMADJ_SU:
+               loginfo->log_interval = MEM_MAX_INTERVAL;
+               break;
+       case OOMADJ_INIT:
+               loginfo->log_interval = MEM_INIT_INTERVAL;
+               break;
+       case OOMADJ_FOREGRD_LOCKED:
+       case OOMADJ_FOREGRD_UNLOCKED:
+       case OOMADJ_BACKGRD_LOCKED:
+               loginfo->log_interval = MEM_FOREGRD_INTERVAL;
+               break;
+       case OOMADJ_BACKGRD_UNLOCKED:
+               loginfo->log_interval = MEM_BACKGRD_INTERVAL;
+               break;
+       default:
+               if (oom > OOMADJ_BACKGRD_UNLOCKED)
+                       loginfo->log_interval = MEM_BACKGRD_OLD_INTERVAL;
+               break;
+       }
+}
+
+static int init_memory_info(void **pl, pid_t pid, int oom, time_t now)
+{
+       struct logging_memory_info *info;
+
+       info = (struct logging_memory_info *)
+                       malloc(sizeof(struct logging_memory_info));
+       if (!info) {
+               _E("malloc for logging_memory_info is failed");
+               return RESOURCED_ERROR_FAIL;
+       }
+       info->current_pid = 0;
+       info->avg_pss = 0;
+       info->max_pss = 0;
+       info->avg_uss = 0;
+       info->max_uss = 0;
+       info->last_log_time = now;
+       info->sampling_count = 0;
+       info->last_commited = false;
+
+       update_log_interval(info, oom, 1);
+       *pl = (void *)info;
+       return RESOURCED_ERROR_NONE;
+}
+
+/* pss_interval should be adjusted depending on app type */
+static int update_memory_info(void *pl, pid_t pid, int oom,
+       time_t now, unsigned always)
+{
+       int ret = RESOURCED_ERROR_NONE;
+       struct logging_memory_info *loginfo = (struct logging_memory_info *)pl;
+       unsigned pss = 0, uss = 0;
+
+       if (!always)
+               if (now < loginfo->last_log_time + loginfo->log_interval)
+                       return ret;
+
+       ret = get_pss(pid, &pss, &uss);
+
+       if (ret != RESOURCED_ERROR_NONE)
+               return ret;
+
+       loginfo->avg_pss = (loginfo->avg_pss * loginfo->sampling_count +
+                       pss)/(loginfo->sampling_count + 1);
+       loginfo->avg_uss = (loginfo->avg_uss * loginfo->sampling_count +
+                       uss)/(loginfo->sampling_count + 1);
+       if (pss > loginfo->max_pss)
+               loginfo->max_pss = pss;
+       if (uss > loginfo->max_uss)
+               loginfo->max_uss = uss;
+
+       loginfo->sampling_count++;
+       loginfo->last_log_time = now;
+       loginfo->last_commited = false;
+       update_log_interval(loginfo, oom, 0);
+
+       return ret;
+}
+
+static int write_memory_info(char *name, struct logging_infos *infos,
+       int ss_index)
+{
+       struct logging_memory_info *mi = infos->stats[ss_index];
+
+       if (!infos->running && mi->last_commited)
+               return RESOURCED_ERROR_NONE;
+
+       sd_journal_send("NAME=memory",
+               "TIME=%ld", mi->last_log_time,
+               "PNAME=%s", name,
+               "AVG_PSS=%lu", mi->avg_pss,
+               "MAX_PSS=%lu", mi->max_pss,
+               "AVG_USS=%lu", mi->avg_uss,
+               "MAX_USS=%lu", mi->max_uss,
+               NULL);
+
+       mi->last_commited = true;
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct logging_info_ops memory_info_ops = {
+       .update = update_memory_info,
+       .write  = write_memory_info,
+       .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();
+
+       if (ret != RESOURCED_ERROR_NONE) {
+               _E("allocate structures 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();
+               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();
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       _D("logging memory init finished");
+       return RESOURCED_ERROR_NONE;
+}
+
+static int logging_memory_exit(void *data)
+{
+       _D("logging memory finalize");
+       free_memory();
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops logging_memory_ops = {
+       .priority       = MODULE_PRIORITY_NORMAL,
+       .name           = "logging_memory",
+       .init           = logging_memory_init,
+       .exit           = logging_memory_exit,
+};
+
+MODULE_REGISTER(&logging_memory_ops)
index 27422d5..d262625 100644 (file)
@@ -91,9 +91,10 @@ static void lowmem_dbus_oom_trigger(void *data, DBusMessage *msg)
 {
        DBusError err;
        int ret;
+       int launching = 0;
+       int flags = OOM_FORCE;
 
        ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_OOM, SIGNAL_NAME_OOM_TRIGGER);
-
        if (ret == 0) {
                _D("there is no oom trigger signal");
                return;
@@ -101,12 +102,15 @@ static void lowmem_dbus_oom_trigger(void *data, DBusMessage *msg)
 
        dbus_error_init(&err);
 
-       if (ret == 0) {
-               _D("there is no message");
-               return;
-       }
+       ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &launching, DBUS_TYPE_INVALID);
+
+       if (launching)
+               flags |= OOM_NOMEMORY_CHECK;
 
-       lowmem_oom_killer_cb(MEMCG_MEMORY, 1);
+       change_memory_state(MEMNOTIFY_LOW, 1);
+       lowmem_oom_killer_cb(MEMCG_MEMORY, flags);
+       _D("flags = %d", flags);
+       change_memory_state(MEMNOTIFY_NORMAL, 0);
 }
 
 void lowmem_dbus_init(void)
index f76bf73..6dd6466 100644 (file)
 #include "proc-main.h"
 #include "lowmem-handler.h"
 #include "proc-process.h"
+#include "swap-common.h"
 #include "lowmem-common.h"
 #include "resourced.h"
 #include "macro.h"
 #include "module.h"
+#include "notifier.h"
 
 enum {
        MEMGC_OOM_NORMAL,
+       MEMGC_OOM_SOFTSWAP,
        MEMGC_OOM_WARNING,
        MEMGC_OOM_HIGH,
        MEMGC_OOM_CRITICAL,
@@ -64,7 +67,14 @@ enum {
        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"
@@ -85,6 +95,7 @@ enum {
 #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
@@ -92,6 +103,7 @@ enum {
 #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 */
@@ -190,6 +202,86 @@ static struct memcg_class memcg_class[MEMCG_GROUP_MAX] = {
                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)
+{
+       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;
+}
+
+void lowmem_dynamic_process_killer(int type)
+{
+       /* This function is not supported */
+}
+
+void change_memory_state(int state, int force)
+{
+       int mem_state;
+
+       if (force) {
+               mem_state = state;
+       } else {
+               mem_state = cur_mem_state;
+               _D("mem_state = %d", mem_state);
+       }
+
+       switch (mem_state) {
+       case MEMNOTIFY_NORMAL:
+               memory_normal_act(NULL);
+               break;
+       case MEMNOTIFY_RECLAIM:
+               memory_reclaim_act(NULL);
+               break;
+       case MEMNOTIFY_LOW:
+               memory_low_act(NULL);
+               break;
+       case MEMNOTIFY_CRITICAL:
+               memory_oom_act(NULL);
+               break;
+       default:
+               assert(0);
+       }
+}
+
 static unsigned int _get_total_memory(void)
 {
        char buf[PATH_MAX];
@@ -491,6 +583,7 @@ static int lowmem_set_threshold(void)
        f = fopen(SET_THRESHOLD_RECLAIM, "w");
 
        if (!f) {
+               _E("Fail to file open : current kernel can't support swap cgroup");
                return RESOURCED_ERROR_FAIL;
        }
 
@@ -593,6 +686,7 @@ void *_lowmem_oom_killer_cb(void *data)
                if (BtoMB(total_size) > MEM_LEAVE_THRESHOLD && oom_score_adj < OOMADJ_BACKGRD_UNLOCKED)
                        continue;
 
+               proc_remove_process_list(pid);
                kill(pid, SIGKILL);
 
                total_size += pid_size[i];
@@ -619,10 +713,11 @@ void *_lowmem_oom_killer_cb(void *data)
        return NULL;
 }
 
-void lowmem_oom_killer_cb(int memcg_idx)
+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)
@@ -676,6 +771,7 @@ static void lowmem_cgroup_oom_killer(int memcg_index)
                if (i==0)
                        make_memps_log(MEMPS_LOG_FILE, pid, appname);
 
+               proc_remove_process_list(pid);
                kill(pid, SIGTERM);
 
                total_size += pid_size[i];
@@ -716,6 +812,30 @@ 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)
 {
@@ -729,6 +849,9 @@ static int memory_reclaim_act(void *data)
        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;
 }
 
@@ -738,7 +861,6 @@ static int memory_low_act(void *data)
        print_mem_state();
        remove_shm();
 
-
        vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
                      VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING);
 
@@ -859,7 +981,6 @@ static Eina_Bool lowmem_cb(void *data, Ecore_Fd_Handler *fd_handler)
                memcg_class[i].oomlevel = currentoom;
        }
 
-
        return ECORE_CALLBACK_RENEW;
 }
 
@@ -905,7 +1026,7 @@ static int setup_eventfd(void)
                        return RESOURCED_ERROR_FAIL;
                }
 
-               /* threshold lv 1 */
+               /* 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);
@@ -1046,10 +1167,12 @@ static void lowmem_move_memcgroup(int pid, int oom_score_adj)
 {
        char buf[LOWMEM_PATH_MAX] = {0,};
        FILE *f;
-       int size;
+       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)
@@ -1057,16 +1180,21 @@ static void lowmem_move_memcgroup(int pid, int oom_score_adj)
        else
                return;
 
-       _I("buf : %s, pid : %d, oom : %d", buf, pid, oom_score_adj);
-       f = fopen(buf, "w");
-       if (!f) {
-               _E("%s open failed", buf);
-               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);
        }
-       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();
 }
 
 static void lowmem_cgroup_foregrd_manage(int currentpid)
@@ -1154,7 +1282,7 @@ static int lowmem_fd_start(void)
 
 int lowmem_init(void)
 {
-       int ret;
+       int ret = RESOURCED_ERROR_NONE;
 
        /* set default memcg value */
        ret = init_memcg();
@@ -1186,6 +1314,8 @@ int lowmem_init(void)
        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;
@@ -1226,6 +1356,8 @@ static int resourced_memory_control(void *data)
 
 static int resourced_memory_init(void *data)
 {
+       lowmem_ops = &memory_modules_ops;
+
        return lowmem_init();
 }
 
@@ -1234,7 +1366,20 @@ static int resourced_memory_finalize(void *data)
        return RESOURCED_ERROR_NONE;
 }
 
-static struct module_ops memory_modules_ops = {
+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;
+}
+
+static const struct module_ops memory_modules_ops = {
        .priority       = MODULE_PRIORITY_NORMAL,
        .name           = "lowmem",
        .init           = resourced_memory_init,
index 2476c40..d938ddd 100644 (file)
 #ifndef __LOWMEM_HANDLER_H__
 #define __LOWMEM_HANDLER_H__
 
-void lowmem_cgroup_foregrd_manage(int currentpid);
-void lowmem_move_memcgroup(int pid, int oom_score_adj);
-int lowmem_init(void);
 void lowmem_dbus_init(void);
-void lowmem_oom_killer_cb(int memcg_idx, int force); /* vmpressure-* version */
+int lowmem_oom_killer_cb(int memcg_idx, int flags);
+void lowmem_dynamic_process_killer(int type);
+unsigned int get_available(void);
+void change_memory_state(int state, int force);
 
 void set_threshold(int level, int thres);
 void set_leave_threshold(int thres);
@@ -43,4 +43,25 @@ enum {
        MEMCG_MAX_GROUPS,
 };
 
+enum {
+       MEMNOTIFY_NORMAL,
+       MEMNOTIFY_SWAP,
+       MEMNOTIFY_LOW,
+       MEMNOTIFY_MEDIUM,
+       MEMNOTIFY_MAX_LEVELS,
+};
+
+enum oom_killer_cb_flags {
+       OOM_NONE                = 0x00000000,   /* for main oom killer thread */
+       OOM_FORCE               = 0x00000001,   /* for forced kill */
+       OOM_TIMER_CHECK         = 0x00000002,   /* for timer oom killer cb */
+       OOM_NOMEMORY_CHECK      = 0x00000004,   /* check victims' memory */
+};
+
+enum {
+       DYNAMIC_KILL_LARGEHEAP,
+       DYNAMIC_KILL_LUNCH,
+       DYNAMIC_KILL_MAX,
+};
+
 #endif /*__LOWMEM_HANDLER_H__*/
diff --git a/src/memory/lowmem-process.c b/src/memory/lowmem-process.c
deleted file mode 100644 (file)
index 09d7a65..0000000
+++ /dev/null
@@ -1,376 +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.
- *
-*/
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/types.h>
-
-#include "resourced.h"
-#include "trace.h"
-#include "proc-main.h"
-#include "lowmem-process.h"
-#include "lowmem-handler.h"
-#include "macro.h"
-#include "proc-noti.h"
-#include "proc-winstate.h"
-
-#define PROC_NAME_MAX 512
-#define PROC_BUF_MAX  64
-#define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
-
-static int lowmem_backgrd_manage(int currentpid)
-{
-       int pid = -1, pgid, ret;
-       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 cur_oom = -1, prev_oom=OOMADJ_BACKGRD_UNLOCKED, select_pid=0;
-       static int checkprevpid = 0;
-
-       ret = lowmem_get_proc_cmdline(currentpid, appname);
-       if (ret == RESOURCED_ERROR_NONE) {
-               if (checkprevpid == currentpid) {
-                       _D("BACKGRD MANAGE : don't manage background application by %d", currentpid);
-                       return RESOURCED_ERROR_NONE;
-               }
-       }
-
-       dp = opendir("/proc");
-       if (!dp) {
-               _E("BACKGRD MANAGE : fail to open /proc");
-               return RESOURCED_ERROR_FAIL;
-       }
-       while ((dentry = readdir(dp)) != NULL) {
-               if (!isdigit(dentry->d_name[0]))
-                       continue;
-
-               pid = atoi(dentry->d_name);
-               pgid = getpgid(pid);
-               if (!pgid)
-                       continue;
-
-               if (currentpid != pid && currentpid == pgid) {
-                       _D("found owner pid = %d, pgid = %d", pid, pgid);
-                       lowmem_move_memcgroup(pid, OOMADJ_BACKGRD_UNLOCKED);
-                       continue;
-               }
-
-               if (select_pid != pid && select_pid == pgid && count < 16)
-               {
-                       _D("found candidate child pid = %d, pgid = %d", pid, 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);
-               if (cur_oom > OOMADJ_BACKGRD_UNLOCKED && cur_oom > prev_oom) {
-                       count = 0;
-                       
-                       select_pid = pid;
-                       prev_oom = cur_oom;
-               }
-
-               if (cur_oom >= OOMADJ_APP_MAX) {
-                       fclose(fp);
-                       continue;
-               } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
-                       _D("BACKGRD : process %d set oom_score_adj %d (before %d)",
-                                       pid, cur_oom+OOMADJ_APP_INCREASE, cur_oom);
-                       fprintf(fp, "%d", cur_oom+OOMADJ_APP_INCREASE);
-               }
-               fclose(fp);
-       }
-       checkprevpid = currentpid;
-       closedir(dp);
-       return RESOURCED_ERROR_OK;
-}
-
-static void lowmem_foregrd_manage(int pid)
-{
-       lowmem_cgroup_foregrd_manage(pid);
-}
-
-int lowmem_sweep_memory(int callpid)
-{
-       int pid = -1, count=0, ret;
-       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 cur_oom = -1;
-       dp = opendir("/proc");
-       if (!dp) {
-               _E("BACKGRD MANAGE : fail to open /proc");
-               return RESOURCED_ERROR_FAIL;
-       }
-       while ((dentry = readdir(dp)) != NULL) {
-               if (!isdigit(dentry->d_name[0]))
-                       continue;
-
-               pid = atoi(dentry->d_name);
-               if (pid == callpid)
-                       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);
-               if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
-                       ret = lowmem_get_proc_cmdline(pid, appname);
-                       if (ret != 0) {
-                               fclose(fp);
-                               continue;
-                       }
-                       kill(pid, SIGKILL);
-                       _D("sweep memory : background process %d(%s) killed",
-                                       pid, appname);
-                       count++;
-               }
-               fclose(fp);
-       }
-       closedir(dp);
-       return count;
-}
-
-
-int lowmem_get_proc_cmdline(pid_t pid, char *cmdline)
-{
-       char buf[PROC_BUF_MAX];
-       char cmdline_buf[PROC_NAME_MAX];
-       char *filename;
-       FILE *fp;
-
-       sprintf(buf, "/proc/%d/cmdline", pid);
-       fp = fopen(buf, "r");
-       if (fp == NULL)
-               return RESOURCED_ERROR_FAIL;
-
-       if (fgets(cmdline_buf, PROC_NAME_MAX-1, fp) == NULL) {
-               fclose(fp);
-               return RESOURCED_ERROR_FAIL;
-       }
-       fclose(fp);
-
-       filename = strrchr(cmdline_buf, '/');
-       if (filename == NULL)
-               filename = cmdline_buf;
-       else
-               filename = filename + 1;
-
-       strncpy(cmdline, filename, PROC_NAME_MAX-1);
-
-       return RESOURCED_ERROR_NONE;
-}
-
-
-int get_proc_oom_score_adj(int pid, int *oom_score_adj)
-{
-       char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
-       FILE *fp = NULL;
-
-       if (pid < 0)
-               return RESOURCED_ERROR_FAIL;
-
-       snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
-       fp = fopen(buf, "r");
-       if (fp == NULL)
-               return RESOURCED_ERROR_FAIL;
-       if (fgets(buf, sizeof(buf), fp) == NULL) {
-               fclose(fp);
-               return RESOURCED_ERROR_FAIL;
-       }
-       (*oom_score_adj) = atoi(buf);
-       fclose(fp);
-       return RESOURCED_ERROR_OK;
-}
-
-int set_proc_oom_score_adj(int pid, int oom_score_adj)
-{
-       char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
-       FILE *fp;
-
-       snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
-       fp = fopen(buf, "r+");
-       if (fp == NULL)
-               return RESOURCED_ERROR_FAIL;
-       if (fgets(buf, sizeof(buf), fp) == NULL) {
-               fclose(fp);
-               return RESOURCED_ERROR_FAIL;
-       }
-       fprintf(fp, "%d", oom_score_adj);
-       fclose(fp);
-
-       lowmem_move_memcgroup(pid, oom_score_adj);
-       return 0;
-}
-
-int lowmem_set_foregrd(int pid, int oom_score_adj)
-{
-       int ret = 0;
-
-       switch (oom_score_adj) {
-       case OOMADJ_FOREGRD_LOCKED:
-       case OOMADJ_FOREGRD_UNLOCKED:
-       case OOMADJ_SU:
-               ret = 0;
-               break;
-       case OOMADJ_BACKGRD_LOCKED:
-               lowmem_foregrd_manage(pid);
-               ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
-               break;
-       case OOMADJ_BACKGRD_UNLOCKED:
-               lowmem_foregrd_manage(pid);
-               ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
-               break;
-       case OOMADJ_INIT:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
-               break;
-       default:
-               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
-                       ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
-               } else {
-                       _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
-                       ret = -1;
-               }
-               break;
-
-       }
-       return ret;
-}
-
-int lowmem_set_backgrd(int pid, int oom_score_adj)
-{
-       int ret = 0;
-
-       switch (oom_score_adj) {
-       case OOMADJ_BACKGRD_LOCKED:
-       case OOMADJ_BACKGRD_UNLOCKED:
-       case OOMADJ_SU:
-               _D("don't change oom value pid = (%d) oom_score_adj (%d)!", pid, oom_score_adj);
-               ret = -1;
-               break;
-       case OOMADJ_FOREGRD_LOCKED:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
-               break;
-       case OOMADJ_FOREGRD_UNLOCKED:
-               lowmem_backgrd_manage(pid);
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
-               break;
-       case OOMADJ_INIT:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
-               break;
-       default:
-               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
-                       ret = 0;
-               } else {
-                       _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
-                       ret = -1;
-               }
-               break;
-       }
-       return ret;
-}
-
-int lowmem_set_active(int pid, int oom_score_adj)
-{
-       int ret = 0;
-
-       switch (oom_score_adj) {
-       case OOMADJ_FOREGRD_LOCKED:
-       case OOMADJ_BACKGRD_LOCKED:
-       case OOMADJ_SU:
-               /* don't change oom value pid */
-               ret = -1;
-               break;
-       case OOMADJ_FOREGRD_UNLOCKED:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
-               break;
-       case OOMADJ_BACKGRD_UNLOCKED:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
-               break;
-       case OOMADJ_INIT:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
-               break;
-       default:
-               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
-                       ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
-               } else {
-                       _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
-                       ret = -1;
-               }
-               break;
-       }
-       return ret;
-}
-
-int lowmem_set_inactive(int pid, int oom_score_adj)
-{
-       int ret = 0;
-
-       switch (oom_score_adj) {
-       case OOMADJ_FOREGRD_UNLOCKED:
-       case OOMADJ_BACKGRD_UNLOCKED:
-       case OOMADJ_SU:
-               /* don't change oom value pid */
-               ret = -1;
-               break;
-       case OOMADJ_FOREGRD_LOCKED:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
-               break;
-       case OOMADJ_BACKGRD_LOCKED:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
-               break;
-       case OOMADJ_INIT:
-               ret = set_proc_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
-               break;
-       default:
-               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
-                       ret = 0;
-               } else {
-                       _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
-                       ret = -1;
-               }
-               break;
-
-       }
-       return ret;
-}
diff --git a/src/memory/lowmem-process.h b/src/memory/lowmem-process.h
deleted file mode 100644 (file)
index 6f67cec..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  resourced
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/**
- * @file lowmem_process.h
- * @desc grouping process and setting oom adj value
- **/
-
-#ifndef __LOWMEM_PROCESS_H__
-#define __LOWMEM_PROCESS_H__
-
-#include <proc_stat.h>
-
-#define OOMADJ_SU                   (0)
-#define OOMADJ_INIT                 (100)
-#define OOMADJ_FOREGRD_LOCKED       (150)
-#define OOMADJ_FOREGRD_UNLOCKED     (200)
-#define OOMADJ_BACKGRD_LOCKED       (250)
-#define OOMADJ_BACKGRD_UNLOCKED     (300)
-#define OOMADJ_APP_LIMIT            OOMADJ_INIT
-#define OOMADJ_APP_MAX              (990)
-#define OOMADJ_APP_INCREASE         (30)
-
-int lowmem_get_proc_cmdline(pid_t pid, char *cmdline);
-int lowmem_sweep_memory(int callpid);
-
-int get_proc_oom_score_adj(int pid, int *oom_score_adj);
-int set_proc_oom_score_adj(int pid, int oom_score_adj);
-
-int lowmem_set_foregrd(int pid, int oom_score_adj);
-int lowmem_set_backgrd(int pid, int oom_score_adj);
-
-int lowmem_set_active(int pid, int oom_score_adj);
-int lowmem_set_inactive(int pid, int oom_score_adj);
-
-int lowmem_get_candidate_pid(void);
-
-#endif /*__LOWMEM_PROCESS_H__*/
diff --git a/src/memory/memory.conf b/src/memory/memory.conf
deleted file mode 100644 (file)
index 0c81b80..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-[Memory64]
-# Threshold to start reclaim
-ThresholdLow=8                 # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=5              # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=8               # MB
-
-[Memory256]
-# Threshold to start reclaim
-ThresholdLow=20                        # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=10             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=20              # MB
-
-[Memory512]
-# Threshold to start reclaim
-ThresholdLow=50                # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=40             # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=60              # MB
-
-[Memory1024]
-# Threshold to start reclaim
-ThresholdLow=200               # MB
-
-# Threshold to start low memory killer
-ThresholdMedium=160            # MB
-
-# Threshold to stop low memory killer
-ThresholdLeave=300             # MB
-
index ecd4e51..81751d2 100644 (file)
@@ -5,8 +5,11 @@ PREDEFINE=enlightenment
 PREDEFINE=dbus-daemon
 PREDEFINE=amd
 PREDEFINE=launchpad_preloading_preinitializing_daemon
+PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
 
 [Memory64]
+# Threshold to start swap
+ThresholdSwap=15               # MB
 
 # Threshold to start reclaim
 ThresholdLow=8                 # MB
@@ -20,7 +23,12 @@ ThresholdLeave=8             # MB
 # Foreground limit ratio
 ForegroundRatio=0.6
 
+# Number of max victims
+NumMaxVictims=1
+
 [Memory256]
+# Threshold to start swap
+ThresholdSwap=40               # MB
 
 # Threshold to start reclaim
 ThresholdLow=20                        # MB
@@ -34,21 +42,31 @@ ThresholdLeave=20           # MB
 # Foreground limit ratio
 ForegroundRatio=0.6
 
+# Number of max victims
+NumMaxVictims=2
+
 [Memory512]
+# Threshold to start swap
+ThresholdSwap=100              # MB
 
 # Threshold to start reclaim
-ThresholdLow=50                # MB
+ThresholdLow=60                        # MB
 
 # Threshold to start low memory killer
 ThresholdMedium=40             # MB
 
 # Threshold to stop low memory killer
-ThresholdLeave=60              # MB
+ThresholdLeave=70              # MB
 
 # Foreground limit ratio
 ForegroundRatio=0.6
 
+# Number of max victims
+NumMaxVictims=5
+
 [Memory1024]
+# Threshold to start swap
+ThresholdSwap=300              # MB
 
 # Threshold to start reclaim
 ThresholdLow=200               # MB
@@ -62,7 +80,12 @@ ThresholdLeave=150           # MB
 # Foreground limit ratio
 ForegroundRatio=0.6
 
+# Number of max victims
+NumMaxVictims=5
+
 [Memory2048]
+# Threshold to start swap
+ThresholdSwap=300              # MB
 
 # Threshold to start reclaim
 ThresholdLow=200               # MB
@@ -75,3 +98,6 @@ ThresholdLeave=300            # MB
 
 # Foreground limit ratio
 ForegroundRatio=0.6
+
+# Number of max victims
+NumMaxVictims=10
index 9155fa3..f821ba2 100644 (file)
@@ -5,8 +5,11 @@ PREDEFINE=enlightenment
 PREDEFINE=dbus-daemon
 PREDEFINE=amd
 PREDEFINE=launchpad_preloading_preinitializing_daemon
+PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
 
 [Memory64]
+# Threshold to start swap
+ThresholdSwap=15               # MB
 
 # Threshold to start reclaim
 ThresholdLow=8                 # MB
@@ -21,6 +24,8 @@ ThresholdLeave=8              # MB
 ForegroundRatio=1
 
 [Memory256]
+# Threshold to start swap
+ThresholdSwap=40               # MB
 
 # Threshold to start reclaim
 ThresholdLow=20                        # MB
@@ -34,21 +39,31 @@ ThresholdLeave=20           # MB
 # Foreground limit ratio
 ForegroundRatio=1
 
+# Number of max victims
+NumMaxVictims=2
+
 [Memory512]
+# Threshold to start swap
+ThresholdSwap=100              # MB
 
 # Threshold to start reclaim
-ThresholdLow=50                # MB
+ThresholdLow=60                        # MB
 
 # Threshold to start low memory killer
 ThresholdMedium=40             # MB
 
 # Threshold to stop low memory killer
-ThresholdLeave=60              # MB
+ThresholdLeave=70              # MB
 
 # Foreground limit ratio
 ForegroundRatio=1
 
+# Number of max victims
+NumMaxVictims=5
+
 [Memory1024]
+# Threshold to start swap
+ThresholdSwap=300              # MB
 
 # Threshold to start reclaim
 ThresholdLow=200               # MB
@@ -62,7 +77,12 @@ ThresholdLeave=150           # MB
 # Foreground limit ratio
 ForegroundRatio=1
 
+# Number of max victims
+NumMaxVictims=5
+
 [Memory2048]
+# Threshold to start swap
+ThresholdSwap=300              # MB
 
 # Threshold to start reclaim
 ThresholdLow=200               # MB
@@ -75,3 +95,6 @@ ThresholdLeave=300            # MB
 
 # Foreground limit ratio
 ForegroundRatio=1
+
+# Number of max victims
+NumMaxVictims=10
diff --git a/src/memory/stub-memory.c b/src/memory/stub-memory.c
deleted file mode 100644 (file)
index d0939ed..0000000
+++ /dev/null
@@ -1,74 +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 stub-memory.c
- * @desc Implement memory API stubs
- *
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
- *
- */
-
-#include "lowmem-process.h"
-#include "macro.h"
-#include "proc-main.h"
-#include "resourced.h"
-
-#include <string.h>
-
-int get_proc_oom_score_adj(UNUSED int pid, UNUSED int *oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int set_proc_oom_score_adj(UNUSED int pid, UNUSED int oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_set_active(UNUSED int pid, UNUSED int oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_set_inactive(UNUSED int pid, UNUSED int oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_set_foregrd(UNUSED int pid, UNUSED int oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_set_backgrd(UNUSED int pid, UNUSED int oom_score_adj)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_sweep_memory(UNUSED int callpid)
-{
-       return RESOURCED_ERROR_NONE;
-}
-
-int lowmem_get_proc_cmdline(UNUSED pid_t pid, char *cmdline)
-{
-       strncpy(cmdline, "", PROC_NAME_MAX-1);
-       return RESOURCED_ERROR_NONE;
-}
index fb0d69f..0c0db5c 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 #include <stdio.h>
-#include <stdbool.h>
 #include <fcntl.h>
 #include <assert.h>
 #include <limits.h>
@@ -34,7 +33,6 @@
 #include <unistd.h>
 #include <time.h>
 #include <limits.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/eventfd.h>
 #include <sys/sysinfo.h>
 #include <Ecore.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "trace.h"
+#include "cgroup.h"
 #include "proc-main.h"
 #include "lowmem-handler.h"
 #include "proc-process.h"
+#include "swap-common.h"
 #include "lowmem-common.h"
 #include "resourced.h"
 #include "macro.h"
+#include "notifier.h"
 #include "config-parser.h"
 #include "module.h"
+#include "logging-common.h"
 
 #define MEMINFO_PATH                   "/proc/meminfo"
 #define MEMCG_PATH                     "/sys/fs/cgroup"
-#define MEMPS_LOG_FILE                 "/var/log/memps"
+#define MEMPS_LOG_PATH                 "/var/log/"
+#define MEMPS_LOG_FILE                 MEMPS_LOG_PATH"memps"
 #define MEMPS_EXEC_PATH                        "usr/bin/memps"
 #define MEMCG_MOVE_CHARGE_PATH         "memory.move_charge_at_immigrate"
 #define MEMCG_OOM_CONTROL_PATH         "memory.oom_control"
 #define MAX_MEMORY_CGROUP_VICTIMS      10
 #define MAX_CGROUP_VICTIMS             1
 #define OOM_TIMER_INTERVAL             2
-#define MAX_TIMER_CHECK                10
-#define OOM_MULTIKILL_WAIT             (1000*1000)
+#define OOM_MULTIKILL_WAIT             (500*1000)
+#define OOM_SIGKILL_WAIT               1
 #define OOM_SCORE_POINT_WEIGHT         1500
+#define OOM_KILLER_PRIORITY            -20
 #define MAX_FD_VICTIMS                 10
+#define MAX_SWAP_VICTIMS               5
+#define MAX_MEMPS_LOGS                 50
+#define NUM_RM_LOGS                    5
+#define THRESHOLD_MARGIN               10 /* MB */
 
 #define MEM_SIZE_64                    64  /* MB */
 #define MEM_SIZE_256                   256 /* MB */
 #define MEM_SIZE_2048                  2048 /* MB */
 
 /* thresholds for 64M RAM*/
-#define MEMCG_MEMORY_64_THRES_LOW              8 /* MB */
-#define MEMCG_MEMORY_64_THRES_MEDIUM           5 /* MB */
-#define MEMCG_MEMORY_64_THRES_LEAVE            8 /* MB */
+#define DYNAMIC_PROCESS_64_THRES               10 /* MB */
+#define DYNAMIC_PROCESS_64_LEAVE               30 /* MB */
+#define MEMCG_MEMORY_64_THRES_SWAP             15 /* MB */
+#define MEMCG_MEMORY_64_THRES_LOW              8  /* MB */
+#define MEMCG_MEMORY_64_THRES_MEDIUM           5  /* MB */
+#define MEMCG_MEMORY_64_THRES_LEAVE            8  /* MB */
 
 /* thresholds for 256M RAM */
+#define DYNAMIC_PROCESS_256_THRES              50 /* MB */
+#define DYNAMIC_PROCESS_256_LEAVE              80 /* MB */
+#define MEMCG_MEMORY_256_THRES_SWAP            40 /* MB */
 #define MEMCG_MEMORY_256_THRES_LOW             20 /* MB */
 #define MEMCG_MEMORY_256_THRES_MEDIUM          10 /* MB */
 #define MEMCG_MEMORY_256_THRES_LEAVE           20 /* MB */
 
 /* threshold for 512M RAM */
-#define MEMCG_MEMORY_512_THRES_LOW             50 /* MB */
-#define MEMCG_MEMORY_512_THRES_MEDIUM          40 /* MB */
-#define MEMCG_MEMORY_512_THRES_LEAVE           60 /* MB */
+#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 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 more than 1024M RAM */
+#define DYNAMIC_PROCESS_1024_THRES             150 /* MB */
+#define DYNAMIC_PROCESS_1024_LEAVE             300 /* MB */
+#define MEMCG_MEMORY_1024_THRES_SWAP           300 /* MB */
 #define MEMCG_MEMORY_1024_THRES_LOW            200 /* MB */
 #define MEMCG_MEMORY_1024_THRES_MEDIUM         100 /* MB */
 #define MEMCG_MEMORY_1024_THRES_LEAVE          150 /* MB */
 
 /* threshold for more than 2048M RAM */
+#define DYNAMIC_PROCESS_2048_THRES             200 /* MB */
+#define DYNAMIC_PROCESS_2048_LEAVE             500 /* MB */
+#define MEMCG_MEMORY_2048_THRES_SWAP           300 /* MB */
 #define MEMCG_MEMORY_2048_THRES_LOW            200 /* MB */
 #define MEMCG_MEMORY_2048_THRES_MEDIUM         160 /* MB */
 #define MEMCG_MEMORY_2048_THRES_LEAVE          300 /* MB */
 
-enum {
-       MEMNOTIFY_NORMAL,
-       MEMNOTIFY_LOW,
-       MEMNOTIFY_MEDIUM,
-       MEMNOTIFY_MAX_LEVELS,
-};
-
 static int thresholds[MEMNOTIFY_MAX_LEVELS];
+static int dynamic_process_threshold[DYNAMIC_KILL_MAX];
+static int dynamic_process_leave[DYNAMIC_KILL_MAX];
 
 struct task_info {
        pid_t pid;
@@ -160,9 +182,10 @@ struct lowmem_process_entry {
        void (*action) (void);
 };
 
-struct mem_info {
-       unsigned real_free;
-       unsigned reclaimable;
+
+struct victims {
+       int num;
+       pid_t pids[MAX_MEMORY_CGROUP_VICTIMS];
 };
 
 /* low memory action function for cgroup */
@@ -172,6 +195,7 @@ static int compare_bg_victims(const struct task_info *ta, const struct task_info
 static int compare_fg_victims(const struct task_info *ta, const struct task_info *tb);
 /* low memory action function */
 static void normal_act(void);
+static void swap_act(void);
 static void low_act(void);
 static void medium_act(void);
 
@@ -181,10 +205,16 @@ static Eina_Bool medium_cb(void *data);
        { MEMNOTIFY_##c, MEMNOTIFY_##n, act}
 
 static struct lowmem_process_entry lpe[] = {
+       LOWMEM_ENTRY(NORMAL,    SWAP,           swap_act),
        LOWMEM_ENTRY(NORMAL,    LOW,            low_act),
        LOWMEM_ENTRY(NORMAL,    MEDIUM,         medium_act),
+       LOWMEM_ENTRY(SWAP,      NORMAL,         normal_act),
+       LOWMEM_ENTRY(SWAP,      LOW,            low_act),
+       LOWMEM_ENTRY(SWAP,      MEDIUM,         medium_act),
+       LOWMEM_ENTRY(LOW,       SWAP,           swap_act),
        LOWMEM_ENTRY(LOW,       NORMAL,         normal_act),
        LOWMEM_ENTRY(LOW,       MEDIUM,         medium_act),
+       LOWMEM_ENTRY(MEDIUM,    SWAP,           swap_act),
        LOWMEM_ENTRY(MEDIUM,    NORMAL,         normal_act),
        LOWMEM_ENTRY(MEDIUM,    LOW,            low_act),
 };
@@ -220,7 +250,10 @@ static struct memcg_class memcg_class[MEMCG_MAX_GROUPS] = {
 static int evfd[MEMCG_MAX_GROUPS] = {-1, };
 static int cur_mem_state = MEMNOTIFY_NORMAL;
 static Ecore_Timer *oom_check_timer = NULL;
+static Ecore_Timer *oom_sigkill_timer = NULL;
 static pid_t killed_fg_victim;
+static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
+struct victims killed_tasks = {0, {0, }};
 
 static pthread_t       oom_thread      = 0;
 static pthread_mutex_t oom_mutex       = PTHREAD_MUTEX_INITIALIZER;
@@ -228,6 +261,10 @@ static pthread_cond_t      oom_cond        = PTHREAD_COND_INITIALIZER;
 
 static unsigned long totalram;
 static unsigned long ktotalram;
+
+static const struct module_ops memory_modules_ops;
+static const struct module_ops *lowmem_ops;
+
 static inline void get_total_memory(void)
 {
        struct sysinfo si;
@@ -240,18 +277,19 @@ static inline void get_total_memory(void)
        }
 }
 
-static void get_mem_info(struct mem_info *mi)
+unsigned int get_available(void)
 {
        char buf[PATH_MAX];
        FILE *fp;
        char *idx;
-       unsigned int tfree = 0, tactive_file = 0, tinactive_file = 0;
+       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;
+               return available;
        }
 
        while (fgets(buf, PATH_MAX, fp) != NULL) {
@@ -259,27 +297,28 @@ static void get_mem_info(struct mem_info *mi)
                        idx += strlen("MemFree:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tfree = atoi(idx);
-                       tfree >>= 10;
-               } else if((idx = strstr(buf, "Active(file):"))) {
-                       idx += strlen("Active(file):");
+                       free = atoi(idx);
+               } else if ((idx = strstr(buf, "MemAvailable:"))) {
+                       idx += strlen("MemAvailable:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tactive_file = atoi(idx);
-                       tactive_file >>= 10;
-               } else if((idx = strstr(buf, "Inactive(file):"))) {
-                       idx += strlen("Inactive(file):");
+                       available = atoi(idx);
+                       break;
+               } else if((idx = strstr(buf, "Cached:"))) {
+                       idx += strlen("Cached:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tinactive_file = atoi(idx);
-                       tinactive_file >>= 10;
+                       cached = atoi(idx);
                        break;
                }
        }
 
-       mi->real_free = tfree;
-       mi->reclaimable = tactive_file + tinactive_file;
+       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)
@@ -361,36 +400,56 @@ static int get_mem_usage_anon(int idx, unsigned int *result)
        return RESOURCED_ERROR_NONE;
 }
 
-static int remove_shm(void)
+static int memps_file_select(const struct dirent *entry)
 {
-       int maxid, shmid, id;
-       struct shmid_ds shmseg;
-       struct shm_info shm_info;
+   return (strstr(entry->d_name, "memps") ? 1 : 0);
+}
 
-       maxid = shmctl(0, SHM_INFO, (struct shmid_ds *)(void *)&shm_info);
-       if (maxid < 0) {
-               _E("shared mem error\n");
-               return RESOURCED_ERROR_FAIL;
+int compare_func(const struct dirent **a, const struct dirent **b)
+{
+       const char *fn_a = (*a)->d_name;
+       const char *fn_b = (*b)->d_name;
+       char *str_at = strrchr(fn_a, '_') + 1;
+       char *str_bt = strrchr(fn_b, '_') + 1;
+
+       return strcmp(str_at, str_bt);
+}
+
+static void clear_logs(char *dir)
+{
+       struct dirent **namelist;
+       int n, i, ret;
+       char fname[BUF_MAX];
+
+       n = scandir(dir, &namelist, memps_file_select, compare_func);
+       _D("num of log files %d", n);
+       if (n < MAX_MEMPS_LOGS) {
+               while (n--)
+                       free(namelist[n]);
+               free(namelist);
+               return;
        }
 
-       for (id = 0; id <= maxid; id++) {
-               shmid = shmctl(id, SHM_STAT, &shmseg);
-               if (shmid < 0)
-                       continue;
-               if (shmseg.shm_nattch == 0) {
-                       _D("shared memory killer ==> %d killed\n",
-                                 shmid);
-                       shmctl(shmid, IPC_RMID, NULL);
+       for (i = 0; i < n; i++) {
+               if (i < NUM_RM_LOGS) {
+                       strcpy(fname, dir);
+                       strcat(fname, namelist[i]->d_name);
+                       _D("remove log file %s", fname);
+                       ret = remove(fname);
+                       if (ret < 0)
+                               _E("%s file cannot removed", fname);
                }
+
+               free(namelist[i]);
        }
-       return 0;
+       free(namelist);
 }
 
 static void make_memps_log(char *file, pid_t pid, char *victim_name)
 {
        time_t now;
-       struct tm *cur_tm;
-       char new_log[512];
+       struct tm cur_tm;
+       char new_log[BUF_MAX];
        static pid_t old_pid;
 
        if (old_pid == pid)
@@ -398,27 +457,20 @@ static void make_memps_log(char *file, pid_t pid, char *victim_name)
        old_pid = pid;
 
        now = time(NULL);
-       cur_tm = (struct tm *)malloc(sizeof(struct tm));
-       if (cur_tm == NULL) {
-               _E("Fail to memory allocation");
-               return;
-       }
 
-       if (localtime_r(&now, cur_tm) == NULL) {
+       if (localtime_r(&now, &cur_tm) == NULL) {
                _E("Fail to get localtime");
-               free(cur_tm);
                return;
        }
 
        snprintf(new_log, sizeof(new_log),
-                "%s_%s_%d_%.4d%.2d%.2d_%.2d%.2d%.2d.log", file, victim_name,
-                pid, (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);
+                "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, victim_name,
+                pid, (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);
 
-       free(cur_tm);
        if (fork() == 0) {
-               execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-f", new_log, (char *)NULL);
+               execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-r", new_log, (char *)NULL);
                exit(0);
        }
 }
@@ -437,11 +489,11 @@ static int lowmem_check_current_state(int memcg_index)
        }
 
        if (oomleave > usage) {
-               _D("%s : usage : %u, oomleave : %u",
+               _D("%s : usage : %u, leave threshold : %u",
                                __func__, usage, oomleave);
                return RESOURCED_ERROR_NONE;
        } else {
-               _D("%s : usage : %u, oomleave : %u",
+               _D("%s : usage : %u, leave threshold: %u",
                                __func__, usage, oomleave);
                return RESOURCED_ERROR_FAIL;
        }
@@ -490,15 +542,14 @@ static int compare_fg_victims(const struct task_info *ta, const struct task_info
        return ((int)(tb->size) - (int)(ta->size));
 }
 
-static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct task_info *selected,
-                                       unsigned *total_size, unsigned
-                                       should_be_freed, int force)
+static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info *selected,
+       unsigned should_be_freed, int flags)
 {
        FILE *f = NULL;
        char buf[LOWMEM_PATH_MAX] = {0, };
        int i = 0;
-       int sel = nsel;
-       unsigned total_victim_size = *total_size;
+       int num_victims = 0;
+       unsigned total_victim_size = 0;
        char appname[PATH_MAX] = {0, };
 
        GArray *victim_candidates = NULL;
@@ -507,7 +558,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
 
        /* if g_array_new fails, return the current number of victims */
        if (victim_candidates == NULL)
-               return sel;
+               return num_victims;
 
        if (idx == MEMCG_MEMORY) {
                sprintf(buf, "%s/%s/system.slice/cgroup.procs",
@@ -526,7 +577,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
                         * if task read in this cgroup fails,
                         * return the current number of victims
                         */
-                       return sel;
+                       return num_victims;
                }
        }
 
@@ -552,15 +603,13 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
                        continue;
 
                for (i = 0; i < victim_candidates->len; i++) {
-                       struct task_info tsk = g_array_index(victim_candidates,
+                       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;
-                                       g_array_remove_index(victim_candidates, i);
-                                       g_array_append_val(victim_candidates, tsk);
+                       if (getpgid(tpid) == tsk->pgid) {
+                               tsk->size += tsize;
+                               if (tsk->oom_score_adj <= 0 && toom > 0) {
+                                       tsk->pid = tpid;
+                                       tsk->oom_score_adj = toom;
                                }
                                break;
                        }
@@ -583,7 +632,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
        if (victim_candidates->len == 0) {
                g_array_free(victim_candidates, true);
                fclose(f);
-               return sel;
+               return num_victims;
        }
 
        g_array_sort(victim_candidates,
@@ -591,103 +640,217 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
 
        for (i = 0; i < victim_candidates->len; i++) {
                struct task_info tsk;
-               if (sel >= max_victims ||
-                       (!force && total_victim_size >= should_be_freed)) {
+               if (num_victims >= max_victims ||
+                   (!(flags & OOM_NOMEMORY_CHECK) &&
+                       total_victim_size >= should_be_freed)) {
                        break;
                }
+
                tsk = g_array_index(victim_candidates, struct task_info, i);
 
-               selected[sel].pid = tsk.pid;
-               selected[sel].pgid = tsk.pgid;
-               selected[sel].oom_score_adj = tsk.oom_score_adj;
-               selected[sel].size = tsk.size;
-               total_victim_size += tsk.size >> 10;
-               sel++;
+               if (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);
+                               break;
+                       }
+                       available = get_available();
+                       if ((flags & OOM_TIMER_CHECK) &&
+                           (available > thresholds[MEMNOTIFY_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;
+               num_victims++;
        }
 
        g_array_free(victim_candidates, true);
 
        fclose(f);
-       *total_size = total_victim_size;
-       return sel;
+       return num_victims;
+
+}
+
+static inline int is_dynamic_process_killer(int flags) {
+       return ((flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK));
+}
+
+static int lowmem_swap_cgroup_oom_killer(int flags)
+{
+       int ret;
+       char appname[PATH_MAX];
+       int count = 0;
+       char buf[LOWMEM_PATH_MAX] = {0, };
+       FILE *f;
+       unsigned int tsize = 0;
+       int swap_type;
+
+       swap_type = swap_status(SWAP_GET_TYPE, NULL);
+       if (swap_type <= SWAP_OFF)
+               return count;
+
+       sprintf(buf, "%s/memory/swap/cgroup.procs",
+                       MEMCG_PATH);
+
+       f = fopen(buf, "r");
+       if (!f) {
+               _E("%s open failed, %d", buf, f);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       while (fgets(buf, 32, f) != NULL) {
+               pid_t tpid = 0;
+               int toom = 0;
+
+               tpid = atoi(buf);
+
+               if (proc_get_oom_score_adj(tpid, &toom) < 0) {
+                       _D("pid(%d) was already terminated", tpid);
+                       continue;
+               }
+
+               if (!get_mem_usage_by_pid(tpid, &tsize)) {
+                       _D("pid(%d) size is not available\n", tpid);
+                       continue;
+               }
+
+               /* To Do: skip by checking pgid? */
+               if (toom < OOMADJ_BACKGRD_UNLOCKED)
+                       continue;
+
+               ret = proc_get_cmdline(tpid, appname);
+               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",
+                               tpid, appname, toom, tsize);
+               if (is_dynamic_process_killer(flags) &&
+                   count >= MAX_SWAP_VICTIMS)
+                       break;
+       }
+
+       fclose(f);
 
+       _I("number of swap victims = %d\n", count);
+       if (!(flags & OOM_FORCE) && (count >= MAX_SWAP_VICTIMS))
+               usleep(OOM_MULTIKILL_WAIT);
+
+       return count;
 }
 
-/* Find victims: BACKGROUND */
-static int lowmem_get_memory_cgroup_victims(struct task_info *selected, int force)
+/* Find victims: (SWAP -> ) BACKGROUND */
+static int lowmem_get_memory_cgroup_victims(struct task_info *selected,
+       int flags)
 {
-       int i, count = 0;
-       unsigned available, should_be_freed = 0, total_size = 0;
-       struct mem_info mi;
+       int i, swap_victims, count = 0;
+       unsigned int available, should_be_freed = 0;
 
-       if (force ) {
-               count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND, count,
-                               MAX_FD_VICTIMS, selected,
-                               &total_size, 0, force);
+       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);
                return count;
        }
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       available = get_available();
        if (available < memcg_class[MEMCG_MEMORY].thres_leave)
                should_be_freed = memcg_class[MEMCG_MEMORY].thres_leave - available;
 
        _I("should_be_freed = %u MB", should_be_freed);
+       if (should_be_freed == 0 || swap_victims >= num_max_victims)
+               return count;
 
-       if (should_be_freed) {
-               for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
-                       count = lowmem_get_cgroup_victims(i, count,
-                                               MAX_MEMORY_CGROUP_VICTIMS, selected,
-                                               &total_size, should_be_freed,
-                                               force);
-                       if (count >= MAX_MEMORY_CGROUP_VICTIMS || total_size >= should_be_freed)
-                               break;
+       for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
+               if ((flags & OOM_TIMER_CHECK) && i < MEMCG_BACKGROUND &&
+                       available > thresholds[MEMNOTIFY_MEDIUM]) {
+                       _D("in timer, not kill fg app, available %u > threshold %u",
+                               available, thresholds[MEMNOTIFY_MEDIUM]);
+                       return count;
                }
+
+               count = lowmem_get_cgroup_victims(i,
+                               num_max_victims - swap_victims,
+                               selected, should_be_freed, flags);
+               if (count > 0) {
+                       _D("kill %d victims in %s cgroup",
+                               count, memcg_class[i].cgroup_name);
+                       return count;
+               } else
+                       _D("There are no victims to be killed in %s cgroup",
+                                       memcg_class[i].cgroup_name);
+
        }
 
        return count;
 }
 
-static int lowmem_get_victims(int idx, struct task_info *selected, int force)
+static int lowmem_get_victims(int idx, struct task_info *selected,
+       int flags)
 {
        int count = 0;
-       unsigned total_size = 0;
 
        if (idx == MEMCG_MEMORY)
-               count = lowmem_get_memory_cgroup_victims(selected, force);
+               count = lowmem_get_memory_cgroup_victims(selected, flags);
        else
-               count = lowmem_get_cgroup_victims(idx, count,
+               count = lowmem_get_cgroup_victims(idx,
                                        MAX_CGROUP_VICTIMS, selected,
-                                       &total_size,
-                                       memcg_class[idx].thres_leave, force);
+                                       memcg_class[idx].thres_leave,
+                                       flags);
 
        return count;
 }
 
-/* To Do: decide the number of victims based on size */
-void lowmem_oom_killer_cb(int memcg_idx, int force)
+static Eina_Bool send_sigkill_cb(void *data)
 {
-       const pid_t self = getpid();
-       int pid, ret, oom_score_adj, i;
-       char appname[PATH_MAX];
-       unsigned total_size = 0, size;
-       struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
-       int count = 0;
+       int i = 0;
 
-       /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
-       count = lowmem_get_victims(memcg_idx, selected, force);
+       _D("kill by SIGKILL timer tasks num = %d", killed_tasks.num);
 
-       if (count == 0) {
-               _D("get %s cgroup victim is failed",
-               memcg_class[memcg_idx].cgroup_name);
-               return;
+       for (i = 0; i < killed_tasks.num; i++) {
+               kill(killed_tasks.pids[i], SIGKILL);
+               _D("killed %d by SIGKILL", killed_tasks.pids[i]);
        }
 
+       killed_tasks.num = 0;
+       ecore_timer_del(oom_sigkill_timer);
+       oom_sigkill_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
+
+}
+
+static int lowmem_kill_victims(int memcg_idx,
+       int count, struct task_info *selected, int flags)
+{
+       const pid_t self = getpid();
+       int pid, ret, oom_score_adj, i;
+       unsigned total_size = 0, size;
+       char appname[PATH_MAX];
+
        for (i = 0; i < count; i++) {
                /* check current memory status */
-               if (memcg_idx != MEMCG_MEMORY && lowmem_check_current_state(memcg_idx) >= 0)
-                       return;
+               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;
@@ -714,13 +877,16 @@ void lowmem_oom_killer_cb(int memcg_idx, int force)
 
                total_size += size;
 
-               if (force)
+               proc_remove_process_list(pid);
+               if (flags & OOM_FORCE) {
                        kill(pid, SIGTERM);
-               else
+                       if (killed_tasks.num < MAX_MEMORY_CGROUP_VICTIMS)
+                               killed_tasks.pids[killed_tasks.num++] = pid;
+               } else
                        kill(pid, SIGKILL);
 
-               _E("we killed, lowmem lv2 = %d (%s) oom = %d, size = %u KB, victim total size = %u KB\n",
-                               pid, appname, oom_score_adj, size, total_size);
+               _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);
 
                if (memcg_idx >= MEMCG_FOREGROUND &&
                        memcg_idx < MEMCG_BACKGROUND)
@@ -732,12 +898,85 @@ void lowmem_oom_killer_cb(int memcg_idx, int force)
                if (i != 0)
                        make_memps_log(MEMPS_LOG_FILE, pid, appname);
        }
+
+       return count;
+}
+
+int lowmem_oom_killer_cb(int memcg_idx, 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);
+
+       if (count == 0) {
+               _D("get %s cgroup victim is failed",
+               memcg_class[memcg_idx].cgroup_name);
+               return count;
+       }
+
+       count = lowmem_kill_victims(memcg_idx, count, selected, flags);
+       clear_logs(MEMPS_LOG_PATH);
+       logging_control(LOGGING_UPDATE_STATE, NULL);
+
+       return count;
+}
+
+void lowmem_dynamic_process_killer(int type)
+{
+       struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
+       int count = 0;
+       unsigned available = get_available();
+       unsigned should_be_freed;
+       int flags = OOM_FORCE;
+       int swap_victims;
+
+       if (!dynamic_process_threshold[type])
+               return;
+
+       if (available >= dynamic_process_threshold[type])
+               return;
+
+       change_memory_state(MEMNOTIFY_LOW, 1);
+       swap_victims = lowmem_swap_cgroup_oom_killer(flags);
+       if (swap_victims >= MAX_SWAP_VICTIMS)
+               goto start_timer;
+
+       available = get_available();
+       if (available >= dynamic_process_leave[type])
+               return;
+
+       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,
+                       num_max_victims - swap_victims, selected,
+                       should_be_freed, flags);
+
+       if (count == 0) {
+               _D("get victim for dynamic process is failed");
+               return;
+       }
+
+       lowmem_kill_victims(MEMCG_BACKGROUND, count, selected, flags);
+       change_memory_state(MEMNOTIFY_NORMAL, 0);
+
+start_timer:
+       if (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;
 }
 
 static void *lowmem_oom_killer_pthread(void *arg)
 {
        int ret = 0;
 
+       setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
+
        while (1) {
                /*
                 * When signalled by main thread,
@@ -756,8 +995,9 @@ static void *lowmem_oom_killer_pthread(void *arg)
                        break;
                }
 
-               _I("oom thread conditional signal received");
-               lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+               _I("oom thread conditional signal received and start");
+               lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_NONE);
+               _I("lowmem_oom_killer_cb finished");
 
                ret = pthread_mutex_unlock(&oom_mutex);
                if ( ret ) {
@@ -779,6 +1019,9 @@ static char *convert_to_str(int mem_state)
        case MEMNOTIFY_NORMAL:
                tmp = "mem normal";
                break;
+       case MEMNOTIFY_SWAP:
+               tmp = "mem swap";
+               break;
        case MEMNOTIFY_LOW:
                tmp = "mem low";
                break;
@@ -801,6 +1044,32 @@ static void change_lowmem_state(unsigned int mem_state)
        cur_mem_state = 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 void normal_act(void)
 {
        int ret, status;
@@ -815,6 +1084,20 @@ static void normal_act(void)
        change_lowmem_state(MEMNOTIFY_NORMAL);
 }
 
+static void swap_act(void)
+{
+       int ret, status;
+
+       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+       if (ret)
+               _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL)
+               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                               VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+       change_lowmem_state(MEMNOTIFY_SWAP);
+}
+
 static void low_act(void)
 {
        int ret, status;
@@ -825,7 +1108,6 @@ static void low_act(void)
                _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
 
        change_lowmem_state(MEMNOTIFY_LOW);
-       remove_shm();
 
        /* Since vconf for soft warning could be set during low memory check,
         * we set it only when the current status is not soft warning.
@@ -837,11 +1119,10 @@ static void low_act(void)
 
 static Eina_Bool medium_cb(void *data)
 {
-       struct mem_info mi;
-       unsigned available;
+       unsigned int available;
+       int count = 0;
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       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) {
@@ -853,8 +1134,21 @@ static Eina_Bool medium_cb(void *data)
        }
 
        _I("cannot reach leave threshold, timer again");
-       lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+       count = lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_TIMER_CHECK);
 
+       /*
+        * After running oom killer in timer, but there is no victim,
+        * stop timer.
+        */
+       if (!count && available >= thresholds[MEMNOTIFY_MEDIUM] &&
+           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]);
+               normal_act();
+               return ECORE_CALLBACK_CANCEL;
+       }
        return ECORE_CALLBACK_RENEW;
 }
 
@@ -865,25 +1159,15 @@ static void medium_act(void)
        change_lowmem_state(MEMNOTIFY_MEDIUM);
 
        /* signal to lowmem_oom_killer_pthread to start killer */
-       ret = pthread_mutex_lock(&oom_mutex);
-       if ( ret ) {
-               _E("medium_act::pthread_mutex_lock() failed, %d", ret);
-               return;
-       }
-
-       ret = pthread_cond_signal(&oom_cond);
-       if ( ret ) {
-               _E("medium_act::pthread_cond_wait() failed, %d", ret);
-               pthread_mutex_unlock(&oom_mutex);
-               return;
-       }
-
-       _I("send signal lowmem oom killer");
-       ret = pthread_mutex_unlock(&oom_mutex);
-       if ( ret ) {
-               _E("medium_act::pthread_mutex_unlock() failed, %d", ret);
+       ret = pthread_mutex_trylock(&oom_mutex);
+       if (ret) {
+               _E("medium_act::pthread_mutex_trylock() failed, %d, errno: %d", ret, errno);
                return;
        }
+       _I("oom mutex trylock success");
+       pthread_cond_signal(&oom_cond);
+       _I("send signal to oom killer thread");
+       pthread_mutex_unlock(&oom_mutex);
 
        vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
                        VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
@@ -984,7 +1268,7 @@ static void memory_cgroup_medium_act(int memcg_idx)
        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, 0);
+               lowmem_oom_killer_cb(memcg_idx, OOM_NONE);
        }
 }
 
@@ -996,7 +1280,7 @@ static unsigned int lowmem_eventfd_read(int fd)
        return ret;
 }
 
-static unsigned int check_mem_state(unsigned available)
+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--) {
@@ -1007,19 +1291,51 @@ static unsigned int check_mem_state(unsigned available)
        return mem_state;
 }
 
+void change_memory_state(int state, int force)
+{
+       unsigned int available;
+       int mem_state;
+
+       if (force) {
+               mem_state = state;
+       } else {
+               available = get_available();
+               mem_state = check_mem_state(available);
+               _D("available = %u, mem_state = %d", available, mem_state);
+       }
+
+       switch (mem_state) {
+       case MEMNOTIFY_NORMAL:
+               normal_act();
+               break;
+       case MEMNOTIFY_SWAP:
+               swap_act();
+               break;
+       case MEMNOTIFY_LOW:
+               low_act();
+               break;
+       case MEMNOTIFY_MEDIUM:
+               medium_act();
+               break;
+       default:
+               assert(0);
+       }
+}
+
 static void lowmem_handler(void)
 {
-       struct mem_info mi;
-       unsigned available;
+       static unsigned int prev_available;
+       unsigned int available;
        int mem_state;
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       available = get_available();
 
-       mem_state = check_mem_state(available);
-       _D("available = %u, mem_state = %d", available, mem_state);
+       if (prev_available == available)
+               return;
 
+       mem_state = check_mem_state(available);
        lowmem_process(mem_state);
+       prev_available = available;
 }
 
 static void lowmem_cgroup_handler(int memcg_idx)
@@ -1207,53 +1523,80 @@ static int load_mem_config(struct parse_result *result, void *user_data)
        return RESOURCED_ERROR_NONE;
 }
 
-static int set_thresholds(const char * section_name, const struct parse_result *result)
+static int set_memory_config(const char * section_name, const struct parse_result *result)
 {
-       if (!result || !section_name)
-               return -EINVAL;
+       if (!result || !section_name)
+               return -EINVAL;
 
-       if (strcmp(result->section, section_name))
-               return RESOURCED_ERROR_NONE;
+       if (strcmp(result->section, section_name))
+               return RESOURCED_ERROR_NONE;
 
-       if (!strcmp(result->name, "ThresholdLow")) {
-              int value = atoi(result->value);
-              set_threshold(MEMNOTIFY_LOW, value);
-       } else if (!strcmp(result->name, "ThresholdMedium")) {
-              int value = atoi(result->value);
-              set_threshold(MEMNOTIFY_MEDIUM, value);
-       } else if (!strcmp(result->name, "ThresholdLeave")) {
-              int value = atoi(result->value);
-              set_leave_threshold(value);
-       } else if (!strcmp(result->name, "ForegroundRatio")) {
-              float value = atof(result->value);
-              set_foreground_ratio(value);
-       }
-       return RESOURCED_ERROR_NONE;
+       if (!strcmp(result->name, "ThresholdSwap")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_SWAP, value);
+       } else if (!strcmp(result->name, "ThresholdLow")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_LOW, value);
+       } else if (!strcmp(result->name, "ThresholdMedium")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_MEDIUM, value);
+       } else if (!strcmp(result->name, "ThresholdLeave")) {
+               int value = atoi(result->value);
+               set_leave_threshold(value);
+       } else if (!strcmp(result->name, "ForegroundRatio")) {
+               float value = atof(result->value);
+               set_foreground_ratio(value);
+       } else if (!strcmp(result->name, "NumMaxVictims")) {
+               int value = atoi(result->value);
+               num_max_victims = value;
+               _D("set number of max victims as %d", num_max_victims);
+       } else if (!strcmp(result->name, "DynamicThreshold")) {
+               int value = atoi(result->value);
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = value;
+               _D("set dynamic process threshold as %d",
+                       dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
+       } else if (!strcmp(result->name, "DynamicLeave")) {
+               int value = atoi(result->value);
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = value;
+               _D("set dynamic process leave threshold as %d",
+                       dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
+       } else if (!strcmp(result->name, "DynamicThresholdLaunch")) {
+               int value = atoi(result->value);
+               dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = value;
+               _D("set dynamic process threshold as %d",
+                       dynamic_process_threshold[DYNAMIC_KILL_LUNCH]);
+       } else if (!strcmp(result->name, "DynamicLeaveLaunch")) {
+               int value = atoi(result->value);
+               dynamic_process_leave[DYNAMIC_KILL_LUNCH] = value;
+               _D("set dynamic process leave threshold as %d",
+                       dynamic_process_leave[DYNAMIC_KILL_LUNCH]);
+       }
+       return RESOURCED_ERROR_NONE;
 }
 
 static int memory_load_64_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory64", result);
+       return set_memory_config("Memory64", result);
 }
 
 static int memory_load_256_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory256", result);
+       return set_memory_config("Memory256", result);
 }
 
 static int memory_load_512_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory512", result);
+       return set_memory_config("Memory512", result);
 }
 
 static int memory_load_1024_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory1024", result);
+       return set_memory_config("Memory1024", result);
 }
 
 static int memory_load_2048_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory2048", result);
+       return set_memory_config("Memory2048", result);
 }
 
 /* init thresholds depending on total ram size. */
@@ -1265,40 +1608,58 @@ static void init_thresholds(void)
 
        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);
                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);
                config_parse(MEM_CONF_FILE, memory_load_256_config, NULL);
        } else if (total_ramsize <= MEM_SIZE_512) {
                /* set thresholds for ram size 512M */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_THRES;
+               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);
                config_parse(MEM_CONF_FILE, memory_load_512_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);
                config_parse(MEM_CONF_FILE, memory_load_1024_config, NULL);
        } else {
-               /* set thresholds for ram size more than 2G */
+               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);
                config_parse(MEM_CONF_FILE, memory_load_2048_config, NULL);
        }
 
-       for (i = MEMNOTIFY_NORMAL; i < MEMNOTIFY_MAX_LEVELS; i++)
+       for (i = MEMNOTIFY_SWAP; i < MEMNOTIFY_MAX_LEVELS; i++)
                _I("set threshold for %d to %u", i, thresholds[i]);
 
        _I("set thres_leave to %u", memcg_class[MEMCG_MEMORY].thres_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)
@@ -1369,11 +1730,37 @@ static int init_memcg(void)
        return ret;
 }
 
+static void lowmem_check(void)
+{
+       unsigned int available;
+
+       available = get_available();
+       _D("available = %u", available);
 
-static int find_foreground_cgroup(void) {
+       if(cur_mem_state != MEMNOTIFY_SWAP &&
+               (available <= thresholds[MEMNOTIFY_SWAP] &&
+                       available > thresholds[MEMNOTIFY_LOW])) {
+               swap_act();
+
+       }
+}
+
+static int find_foreground_cgroup(struct proc_process_info_t *process_info) {
        int fg, min_fg = -1;
        unsigned int min_usage = UINT_MAX;
 
+       /*
+        * 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 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);
@@ -1395,28 +1782,34 @@ static int find_foreground_cgroup(void) {
        return min_fg;
 }
 
-void lowmem_move_memcgroup(int pid, int oom_score_adj)
+static void lowmem_move_memcgroup(int pid, int oom_score_adj)
 {
        char buf[LOWMEM_PATH_MAX] = {0,};
        FILE *f;
-       int size;
+       int size, background = 0;
+       unsigned long swap_args[1] = {0,};
+       struct proc_process_info_t *process_info =
+               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);
+               background = 1;
        } else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED &&
                                        oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
-               int ret;
-               ret = find_foreground_cgroup();
+               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);
        } else
                return;
 
-
-               _D("buf : %s, pid : %d, oom : %d", buf, pid, oom_score_adj);
+       swap_args[0] = (unsigned long)pid;
+       if (!swap_status(SWAP_CHECK_PID, swap_args) || !background) {
+               _D("buf : %s, pid : %d, score : %d", buf, pid, oom_score_adj);
                f = fopen(buf, "w");
                if (!f) {
                        _E("%s open failed", buf);
@@ -1426,29 +1819,28 @@ void lowmem_move_memcgroup(int pid, int oom_score_adj)
                if (fwrite(buf, size, 1, f) != 1)
                        _E("fwrite cgroup tasks : %d\n", pid);
                fclose(f);
-
+       }
+       if (background) {
+               lowmem_check();
+               lowmem_swap_memory();
+       }
 }
 
-void lowmem_cgroup_foregrd_manage(int currentpid)
+static void lowmem_cgroup_foregrd_manage(int currentpid)
 {
-       char buf[LOWMEM_PATH_MAX] = {0,};
-       int pid, pgid;
-       FILE *f;
-       sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
-       f = fopen(buf, "r");
-       if (!f) {
-               _E("%s open failed", buf);
+       GSList *iter;
+       struct proc_process_info_t *process_info =
+               find_process_info(NULL, currentpid, NULL);
+
+       if (!process_info)
                return;
+
+       gslist_for_each_item(iter, process_info->pids) {
+               struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
+
+               if (pid_info->type == RESOURCED_APP_TYPE_GROUP)
+                       lowmem_move_memcgroup(pid_info->pid, OOMADJ_FOREGRD_UNLOCKED);
        }
-       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);
 }
 
 static int oom_thread_create(void)
@@ -1471,6 +1863,20 @@ static int oom_thread_create(void)
        return ret;
 }
 
+static int lowmem_app_launch_cb(void *data)
+{
+       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;
+
+       if (process_info && !(process_info->type & PROC_LARGE_HEAP))
+               lowmem_dynamic_process_killer(DYNAMIC_KILL_LUNCH);
+       return ret;
+}
+
 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
 int lowmem_init(void)
 {
@@ -1507,6 +1913,7 @@ int lowmem_init(void)
        }
 
        lowmem_dbus_init();
+       register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
 
        return ret;
 }
@@ -1533,15 +1940,31 @@ 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;
+}
+
+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;
 }
 
-static struct module_ops memory_modules_ops = {
+static const struct module_ops memory_modules_ops = {
        .priority       = MODULE_PRIORITY_NORMAL,
        .name           = "lowmem",
        .init           = resourced_memory_init,
diff --git a/src/memps/CMakeLists.txt b/src/memps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..83e6fca
--- /dev/null
@@ -0,0 +1,19 @@
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+
+IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(SOURCES ${MEMPS_SOURCE_DIR}/memps.c)
+
+ADD_EXECUTABLE(memps ${MEMPS_SOURCE_DIR}/memps.c)
+INSTALL(TARGETS memps DESTINATION /usr/bin)
+
+
diff --git a/src/memps/memps.c b/src/memps/memps.c
new file mode 100644 (file)
index 0000000..bc7b752
--- /dev/null
@@ -0,0 +1,1124 @@
+/*
+   Copyright (c) 2000 - 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.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.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>
+
+#define STR_SGX_PATH   "/dev/pvrsrvkm"
+#define STR_3D_PATH1   "/dev/mali"
+#define STR_3D_PATH2   "/dev/kgsl-3d0"
+#define STR_DRM_PATH1  "/drm mm object (deleted)"
+#define STR_DRM_PATH2  "/dev/dri/card0"
+
+#define BUF_MAX         (BUFSIZ)            /* most optimal for libc::stdio */
+#define BUF_INC_SIZE    (512 * 1024)        /* maximal SMAPS I saw 2 MB     */
+#define KB(bytes)       ((bytes)/1024)
+
+typedef struct geminfo geminfo;
+typedef struct mapinfo mapinfo;
+typedef struct trib_mapinfo trib_mapinfo;
+
+enum {
+       OUTPUT_UART,
+       OUTPUT_FILE,
+       NUM_OUTPUT_TYPE
+};
+
+struct mapinfo {
+       mapinfo *next;
+       unsigned start;
+       unsigned end;
+       unsigned size;
+       unsigned rss;
+       unsigned pss;
+       unsigned shared_clean;
+       unsigned shared_dirty;
+       unsigned private_clean;
+       unsigned private_dirty;
+       char perm[4];
+       char name[1];
+};
+
+/* classify normal, graphic and other devices memory */
+struct trib_mapinfo {
+       unsigned shared_clean;
+       unsigned shared_dirty;
+       unsigned private_clean;
+       unsigned private_dirty;
+       unsigned shared_clean_pss;
+       unsigned shared_dirty_pss;
+       unsigned rss;
+       unsigned pss;
+       unsigned size;
+       unsigned graphic_3d;
+       unsigned gem_rss;
+       unsigned gem_pss;
+       unsigned peak_rss;
+       unsigned other_devices;
+       unsigned gem_mmap;
+};
+
+struct geminfo {
+       geminfo *next;
+       unsigned int tgid;
+       unsigned rss_size;
+       unsigned pss_size;
+       unsigned hcount;
+};
+
+static int ignore_smaps_field;
+static int sum;
+static int verbos;
+
+/* reads file contents into memory */
+static char* cread(const char* path)
+{
+       /* once allocated area for reads */
+       static char*    text = NULL;
+       static size_t   size = 0;
+
+       ssize_t ret;
+       char*   ptr = text;
+       size_t  cap = size;
+       int     fd  = open(path, O_RDONLY);
+
+       if (fd < 0) {
+               return NULL;
+       }
+
+       do {
+               /* ensure we have enough space */
+               if (cap == 0) {
+                       ptr = (char*)realloc(text, size + BUF_INC_SIZE);
+                       if (ptr == NULL) {
+                               ret = -1;
+                               break;
+                       }
+
+                       text  = ptr;
+                       ptr   = text + size;
+                       cap   = BUF_INC_SIZE;
+                       size += BUF_INC_SIZE;
+               }
+               ret = read(fd, ptr, cap);
+               if (ret == 0) {
+                       *ptr = 0;
+               } else if (ret > 0) {
+                       cap -= ret;
+                       ptr += ret;
+               }
+       } while (ret > 0);
+       close(fd);
+
+       return (ret < 0 ? NULL : text);
+} /* cread */
+
+/* like fgets/gets but adjusting contents pointer */
+static inline char* cgets(char** contents)
+{
+       if (contents && *contents && **contents) {
+               char* bos = *contents;          /* begin of string */
+               char* eos = strchr(bos, '\n');  /* end of string   */
+
+               if (eos) {
+                       *contents = eos + 1;
+                       *eos      = 0;
+               } else {
+                       *contents = NULL;
+               }
+               return bos;
+       }
+
+       return NULL;
+} /* cgets */
+
+
+static unsigned get_peak_rss(unsigned int pid)
+{
+       static const char field[] = "VmHWM:";
+       char tmp[128];
+       char* line;
+       char* value;
+
+       sprintf(tmp, "/proc/%d/status", pid);
+       line = cread(tmp);
+       if (line == NULL) {
+               fprintf(stderr, "cannot open %s\n", tmp);
+               return 0;
+       }
+
+       value = strstr(line, field);
+       if (value) {
+               value += sizeof(field);
+               return strtoul(value, NULL, 10);
+       }
+
+       return 0;
+}
+#define NUM_GEM_FIELD 6
+
+static geminfo *read_geminfo(FILE *fp)
+{
+       geminfo *tgeminfo;
+       char line[BUF_MAX];
+       unsigned int pid, tgid, handle, refcount, hcount;
+       unsigned gem_size;
+
+       if (fgets(line, BUF_MAX, fp) != NULL) {
+               if (sscanf(line, "%d %d %d %d %d 0x%x",
+                       &pid, &tgid, &handle, &refcount,
+                       &hcount, &gem_size) != NUM_GEM_FIELD)
+                       return NULL;
+
+               tgeminfo = malloc(sizeof(geminfo));
+               if (tgeminfo == NULL)
+                       return NULL;
+               tgeminfo->tgid = tgid;
+               tgeminfo->hcount = hcount;
+               tgeminfo->rss_size = KB(gem_size);
+               tgeminfo->pss_size = KB(gem_size/tgeminfo->hcount);
+       } else
+               return NULL;
+
+       return tgeminfo;
+}
+
+
+static geminfo *load_geminfo(void)
+{
+       geminfo *ginfo;
+       geminfo *gilist = NULL;
+       FILE *drm_fp;
+       char line[BUF_MAX];
+
+       drm_fp = fopen("/sys/kernel/debug/dri/0/gem_info", "r");
+
+       if (drm_fp == NULL) {
+               fprintf(stderr,
+               "cannot open /sys/kernel/debug/dri/0/gem_info\n");
+               return NULL;
+       }
+
+       if (fgets(line, BUF_MAX, drm_fp) == NULL) {
+               fclose(drm_fp);
+               return NULL;
+       } else {
+               /* we should count a number of whitespace separated fields */
+               int      in_field = (line[0] && !isblank(line[0]));
+               unsigned int size = (unsigned)in_field;
+               const char*  ptr  = &line[1];
+
+               /* sscanf() was used in original code, so number of fields */
+               /* in string is expected to be at least NUM_GEM_FIELD      */
+               while (*ptr && size < NUM_GEM_FIELD) {
+                       if (isblank(*ptr++)) {
+                               if (in_field) {
+                                       /* end of field */
+                                       in_field = 0;
+                               }
+                       } else {
+                               if (!in_field) {
+                                       /* next field started */
+                                       in_field = 1;
+                                       size++;
+                               }
+                       }
+               } /* while */
+
+               if (size != NUM_GEM_FIELD) {
+                       fclose(drm_fp);
+                       return NULL;
+               }
+       }
+
+       while ((ginfo = read_geminfo(drm_fp)) != NULL) {
+               if (gilist && ginfo->tgid == gilist->tgid) {
+                       gilist->pss_size += ginfo->pss_size;
+                       gilist->rss_size += ginfo->rss_size;
+                       free(ginfo);
+                       continue;
+               }
+               ginfo->next = gilist;
+               gilist = ginfo;
+       }
+
+       fclose(drm_fp);
+
+       return gilist;
+}
+
+
+/* 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /android/lib/libcomposer.so
+ * 012345678901234567890123456789012345678901234567890123456789
+ * 0         1         2         3         4         5
+ */
+
+mapinfo *read_mapinfo(char** smaps, int rest_line)
+{
+       char* line;
+       mapinfo *mi;
+       int len;
+       int tmp;
+
+       if ((line = cgets(smaps)) == 0)
+               return 0;
+
+       len    = strlen(line);
+       if (len < 1)
+               return 0;
+
+       mi = malloc(sizeof(mapinfo) + len + 16);
+       if (mi == 0)
+               return 0;
+
+       mi->start = strtoul(line, 0, 16);
+       mi->end = strtoul(line + 9, 0, 16);
+
+       mi->perm[0] = line[18]; /* read */
+       mi->perm[1] = line[19]; /* write */
+       mi->perm[2] = line[20]; /* execute */
+       mi->perm[3] = line[21]; /* may share or private */
+
+       if (len < 50)
+               strcpy(mi->name, "[anon]");
+       else
+               strcpy(mi->name, line + 49);
+
+       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-- && (line = cgets(smaps))) {
+               if (sscanf(line, "PSwap: %d kB", &tmp) == 1)
+                       rest_line++;
+       }
+
+       return mi;
+ oops:
+       printf("mi get error\n");
+       free(mi);
+       return 0;
+}
+
+static unsigned total_gem_memory(void)
+{
+       FILE *gem_fp;
+       unsigned total_gem_mem = 0;
+       unsigned name, size, handles, refcount;
+       char line[BUF_MAX];
+
+       gem_fp = fopen("/proc/dri/0/gem_names", "r");
+       if(gem_fp == NULL) {
+               fprintf(stderr,
+               "cannot open /proc/dir/0/gem_names\n");
+               return 0;
+       }
+
+       if (fgets(line, BUF_MAX, gem_fp) == NULL) {
+               fclose(gem_fp);
+               return 0;
+       }
+
+       while (fgets(line, BUF_MAX, gem_fp) != NULL)
+               if (sscanf(line, "%d %d %d %d\n",
+                   &name, &size, &handles, &refcount) == 4)
+                       total_gem_mem += size;
+       fclose(gem_fp);
+
+       return total_gem_mem;
+}
+
+static void get_mem_info(FILE *output_fp)
+{
+       char buf[PATH_MAX];
+       FILE *fp;
+       char *idx;
+       unsigned int free = 0, cached = 0;
+       unsigned int total_mem = 0, available = 0, used;
+       unsigned int swap_total = 0, swap_free = 0, swap_used;
+       unsigned int used_ratio;
+
+       if (output_fp == NULL)
+               return;
+
+       fp = fopen("/proc/meminfo", "r");
+
+       if (!fp) {
+               fprintf(stderr, "%s open failed, %p", buf, fp);
+               return;
+       }
+
+       while (fgets(buf, PATH_MAX, fp) != NULL) {
+               if ((idx = strstr(buf, "MemTotal:"))) {
+                       idx += strlen("Memtotal:");
+                       while (*idx < '0' || *idx > '9')
+                               idx++;
+                       total_mem = atoi(idx);
+               } else 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);
+               } else if((idx = strstr(buf, "Cached:")) && !strstr(buf, "Swap")) {
+                       idx += strlen("Cached:");
+                       while (*idx < '0' || *idx > '9')
+                               idx++;
+                       cached = atoi(idx);
+               } else if((idx = strstr(buf, "SwapTotal:"))) {
+                       idx += strlen("SwapTotal:");
+                       while (*idx < '0' || *idx > '9')
+                               idx++;
+                       swap_total = atoi(idx);
+               } else if((idx = strstr(buf, "SwapFree:"))) {
+                       idx += strlen("SwapFree");
+                       while (*idx < '0' || *idx > '9')
+                               idx++;
+                       swap_free = atoi(idx);
+                       break;
+               }
+       }
+
+       if (available == 0)
+               available = free + cached;
+       used = total_mem - available;
+       used_ratio = used * 100 / total_mem;
+       swap_used = swap_total - swap_free;
+
+       fprintf(output_fp,
+               "====================================================================\n");
+
+
+       fprintf(output_fp, "Total RAM size: \t%15d MB( %6d kB)\n",
+                       total_mem >> 10, total_mem);
+
+       fprintf(output_fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
+                       (total_mem - free) >> 10, total_mem - free);
+
+       fprintf(output_fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
+                       used >> 10, used);
+
+       fprintf(output_fp, "Used (Mem):  \t\t%15d MB( %6d kB)\n",
+                       used >> 10, used);
+
+       fprintf(output_fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
+                       swap_used >> 10, swap_used);
+
+       fprintf(output_fp, "Used Ratio: \t\t%15d  %%\n", used_ratio);
+
+       fprintf(output_fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
+                       free >> 10, free);
+
+       fprintf(output_fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
+                       available >> 10,
+                       available);
+       fclose(fp);
+}
+
+static int get_tmpfs_info(FILE *output_fp)
+{
+       FILE *fp;
+       char line[BUF_MAX];
+       char tmpfs_mp[NAME_MAX];        /* tmpfs mount point */
+       struct statfs tmpfs_info;
+
+       if (output_fp == NULL)
+               return -1;
+
+       fp = fopen("/etc/mtab", "r");
+       if (fp == NULL)
+               return -1;
+
+       fprintf(output_fp,
+               "====================================================================\n");
+       fprintf(output_fp, "TMPFS INFO\n");
+
+       while (fgets(line, BUF_MAX, fp) != NULL) {
+               if (sscanf(line, "tmpfs %s tmpfs", tmpfs_mp) == 1) {
+                       statfs(tmpfs_mp, &tmpfs_info);
+                       fprintf(output_fp,
+                               "tmpfs %16s  Total %8ld KB, Used %8ld, Avail %8ld\n",
+                               tmpfs_mp,
+                               /* 1 block is 4 KB */
+                               tmpfs_info.f_blocks * 4,
+                               (tmpfs_info.f_blocks - tmpfs_info.f_bfree) * 4,
+                               tmpfs_info.f_bfree * 4);
+               }
+       }
+       fclose(fp);
+       return 0;
+}
+
+mapinfo *load_maps(int pid)
+{
+       char* smaps;
+       char tmp[128];
+       mapinfo *milist = 0;
+       mapinfo *mi;
+
+       sprintf(tmp, "/proc/%d/smaps", pid);
+       smaps = cread(tmp);
+       if (smaps == NULL)
+               return 0;
+
+       while ((mi = read_mapinfo(&smaps, ignore_smaps_field)) != 0) {
+               if (milist) {
+                       if ((!strcmp(mi->name, milist->name)
+                            && (mi->name[0] != '['))) {
+                               milist->size += mi->size;
+                               milist->rss += mi->rss;
+                               milist->pss += mi->pss;
+                               milist->shared_clean += mi->shared_clean;
+                               milist->shared_dirty += mi->shared_dirty;
+                               milist->private_clean += mi->private_clean;
+                               milist->private_dirty += mi->private_dirty;
+
+                               milist->perm[0] = mi->perm[0];
+                               milist->perm[1] = mi->perm[1];
+                               milist->perm[2] = mi->perm[2];
+                               milist->perm[3] = mi->perm[3];
+                               milist->end = mi->end;
+                               strncpy(milist->perm, mi->perm, 4);
+                               free(mi);
+                               continue;
+                       }
+               }
+               mi->next = milist;
+               milist = mi;
+       }
+
+       return milist;
+}
+
+static geminfo *find_geminfo(unsigned int tgid, geminfo *gilist)
+{
+       geminfo *gi;
+       for (gi = gilist; gi; ) {
+               if (gi->tgid == tgid)
+                       return gi;
+
+               gi = gi->next;
+       }
+       return NULL;
+}
+
+static void init_trib_mapinfo(trib_mapinfo *tmi)
+{
+       if (!tmi)
+               return;
+       tmi->shared_clean = 0;
+       tmi->shared_dirty = 0;
+       tmi->private_clean = 0;
+       tmi->private_dirty = 0;
+       tmi->shared_clean_pss = 0;
+       tmi->shared_dirty_pss = 0;
+       tmi->rss = 0;
+       tmi->pss = 0;
+       tmi->size = 0;
+       tmi->graphic_3d = 0;
+       tmi->gem_rss = 0;
+       tmi->gem_pss = 0;
+       tmi->peak_rss = 0;
+       tmi->other_devices = 0;
+       tmi->gem_mmap = 0;
+}
+
+static int
+get_trib_mapinfo(unsigned int tgid, mapinfo *milist,
+                geminfo *gilist, trib_mapinfo *result)
+
+{
+       mapinfo *mi;
+       mapinfo *temp = NULL;
+       geminfo *gi;
+
+       if (!result)
+               return -EINVAL;
+
+       init_trib_mapinfo(result);
+       for (mi = milist; mi;) {
+               if (strstr(mi->name, STR_SGX_PATH)) {
+                       result->graphic_3d += mi->pss;
+               } else if (strstr(mi->name, STR_3D_PATH1) ||
+                       strstr(mi->name, STR_3D_PATH2)) {
+                       result->graphic_3d += mi->size;
+               } else if (mi->rss != 0 && mi->pss == 0
+                          && mi->shared_clean == 0
+                          && mi->shared_dirty == 0
+                          && mi->private_clean == 0
+                          && mi->private_dirty == 0) {
+                       result->other_devices += mi->size;
+               } else if (!strncmp(mi->name, STR_DRM_PATH1,
+                               sizeof(STR_DRM_PATH1)) ||
+                               !strncmp(mi->name, STR_DRM_PATH2,
+                               sizeof(STR_DRM_PATH2))) {
+                       result->gem_mmap += mi->rss;
+               } else {
+                       result->shared_clean += mi->shared_clean;
+                       result->shared_dirty += mi->shared_dirty;
+                       result->private_clean += mi->private_clean;
+                       result->private_dirty += mi->private_dirty;
+                       result->rss += mi->rss;
+                       result->pss += mi->pss;
+                       result->size += mi->size;
+
+                       if(mi->shared_clean != 0)
+                               result->shared_clean_pss += mi->pss;
+                       else if (mi->shared_dirty != 0)
+                               result->shared_dirty_pss += mi->pss;
+               }
+
+               temp = mi;
+               mi = mi->next;
+               free(temp);
+               temp = NULL;
+       }
+
+       result->peak_rss = get_peak_rss(tgid);
+       if (result->peak_rss < result->rss)
+               result->peak_rss = result->rss;
+       if (result->gem_mmap > 0)
+               result->peak_rss -= result->gem_mmap;
+
+       gi = find_geminfo(tgid, gilist);
+       if (gi != NULL) {
+               result->gem_rss = gi->rss_size;
+               result->gem_pss = gi->pss_size;
+       }
+
+       return 0;
+}
+
+static int get_cmdline(unsigned int pid, char *cmdline)
+{
+       FILE *fp;
+       char buf[NAME_MAX] = {0, };
+       int ret = -1;
+
+       sprintf(buf, "/proc/%d/cmdline", pid);
+       fp = fopen(buf, "r");
+       if (fp == 0) {
+               fprintf(stderr, "cannot file open %s\n", buf);
+               return ret;
+       }
+       if ((ret = fscanf(fp, "%s", cmdline)) < 1) {
+               fclose(fp);
+               return ret;
+       }
+       fclose(fp);
+
+       return ret;
+}
+
+static int get_oomscoreadj(unsigned int pid)
+{
+       FILE *fp;
+       char tmp[256];
+       int oomadj_val;
+
+       sprintf(tmp, "/proc/%d/oom_score_adj", pid);
+       fp = fopen(tmp, "r");
+
+       if (fp == NULL) {
+               oomadj_val = -50;
+               return oomadj_val;
+       }
+       if (fgets(tmp, sizeof(tmp), fp) == NULL) {
+               oomadj_val = -100;
+               fclose(fp);
+               return oomadj_val;
+       }
+
+       oomadj_val = atoi(tmp);
+
+       fclose(fp);
+       return oomadj_val;
+}
+
+static void get_rss(pid_t pid, unsigned int *result)
+{
+       FILE *fp;
+       char proc_path[PATH_MAX];
+       int rss = 0;
+
+       *result = 0;
+
+       sprintf(proc_path, "/proc/%d/statm", pid);
+       fp = fopen(proc_path, "r");
+       if (fp == NULL)
+               return;
+
+       if (fscanf(fp, "%*s %d", &rss) < 1) {
+               fclose(fp);
+               return;
+       }
+
+       fclose(fp);
+
+       /* convert page to Kb */
+       *result = rss * 4;
+       return;
+}
+
+static void show_rss(int output_type, char *output_path)
+{
+       DIR *pDir = NULL;
+       struct dirent *curdir;
+       pid_t pid;
+       char cmdline[PATH_MAX];
+       FILE *output_file = NULL;
+       int oom_score_adj;
+       unsigned int rss;
+
+       pDir = opendir("/proc");
+       if (pDir == NULL) {
+               fprintf(stderr, "cannot read directory /proc.\n");
+               return;
+       }
+
+       if (output_type == OUTPUT_FILE && output_path) {
+               output_file = fopen(output_path, "w+");
+               if (!output_file) {
+                       fprintf(stderr, "cannot open output file(%s)\n",
+                               output_path);
+                       closedir(pDir);
+                       exit(1);
+               }
+       } else
+               output_file = stdout;
+
+
+       fprintf(output_file,
+                       "     PID    RSS    OOM_SCORE    COMMAND\n");
+
+       while ((curdir = readdir(pDir)) != NULL) {
+               pid = atoi(curdir->d_name);
+               if (pid < 1 || pid > 32768 || pid == getpid())
+                       continue;
+
+               if (get_cmdline(pid, cmdline) < 0)
+                       continue;
+               get_rss(pid, &rss);
+               oom_score_adj = get_oomscoreadj(pid);
+
+               fprintf(output_file,
+                               "%8d %8u %8d          %s\n",
+                               pid,
+                               rss,
+                               oom_score_adj,
+                               cmdline);
+
+
+       } /* end of while */
+
+       get_tmpfs_info(output_file);
+       get_mem_info(output_file);
+
+       fclose(output_file);
+       closedir(pDir);
+
+       return;
+}
+
+static int show_map_all_new(int output_type, char *output_path)
+{
+       DIR *pDir = NULL;
+       struct dirent *curdir;
+       unsigned int pid;
+       mapinfo *milist;
+       geminfo *glist;
+       unsigned total_pss = 0;
+       unsigned total_private = 0;
+       unsigned total_private_code = 0;
+       unsigned total_private_data = 0;
+       unsigned total_shared_code = 0;
+       unsigned total_shared_data = 0;
+       unsigned total_shared_code_pss = 0;
+       unsigned total_shared_data_pss = 0;
+       unsigned total_rss = 0;
+       unsigned total_graphic_3d = 0;
+       unsigned total_gem_rss = 0;
+       unsigned total_gem_pss = 0;
+       unsigned total_peak_rss = 0;
+       unsigned total_allocated_gem = 0;
+       trib_mapinfo tmi;
+       char cmdline[PATH_MAX];
+       FILE *output_file = NULL;
+       int oom_score_adj;
+
+       pDir = opendir("/proc");
+       if (pDir == NULL) {
+               fprintf(stderr, "cannot read directory /proc.\n");
+               return 0;
+       }
+
+       if (output_type == OUTPUT_FILE && output_path) {
+               output_file = fopen(output_path, "w+");
+               if (!output_file) {
+                       fprintf(stderr, "cannot open output file(%s)\n",
+                               output_path);
+                       closedir(pDir);
+                       exit(1);
+               }
+       } else
+               output_file = stdout;
+
+       glist = load_geminfo();
+
+       if (!sum) {
+               if (verbos)
+                       fprintf(output_file,
+                                       "     PID  S(CODE)  S(DATA)  P(CODE)  P(DATA)"
+                                       "     PEAK      PSS       3D"
+                                       "     GEM(PSS)  GEM(RSS)"
+                                       " OOM_SCORE_ADJ    COMMAND\n");
+               else
+                       fprintf(output_file,
+                                       "     PID     CODE     DATA     PEAK     PSS"
+                                       "     3D      GEM(PSS)      COMMAND\n");
+       }
+
+       while ((curdir = readdir(pDir)) != NULL) {
+               pid = atoi(curdir->d_name);
+               if (pid < 1 || pid > 32768 || pid == getpid())
+                       continue;
+
+               if (get_cmdline(pid, cmdline) < 0)
+                       continue;
+
+               milist = load_maps(pid);
+               if (milist == 0)
+                       continue;
+
+               /* get classified map info */
+               get_trib_mapinfo(pid, milist, glist, &tmi);
+               oom_score_adj = get_oomscoreadj(pid);
+
+               if (!sum) {
+                       if (verbos)
+                               fprintf(output_file,
+                                       "%8d %8d %8d %8d %8d %8d %8d %8d %8d %8d"
+                                       " %8d \t\t%s\n",
+                                       pid,
+                                       tmi.shared_clean, tmi.shared_dirty,
+                                       tmi.private_clean, tmi.private_dirty,
+                                       tmi.peak_rss, tmi.pss, tmi.graphic_3d,
+                                       tmi.gem_pss, tmi.gem_rss, oom_score_adj, cmdline);
+                       else
+                               fprintf(output_file,
+                                       "%8d %8d %8d %8d %8d %8d %8d      %s\n",
+                                       pid,
+                                       tmi.shared_clean +
+                                       tmi.private_clean,
+                                       tmi.shared_dirty + tmi.private_dirty,
+                                       tmi.peak_rss,
+                                       tmi.pss,
+                                       tmi.graphic_3d,
+                                       tmi.gem_pss, cmdline);
+
+                       if (tmi.other_devices != 0)
+                               fprintf(output_file,
+                                       "%s(%d) %d KB may mapped by device(s).\n",
+                                       cmdline, pid, tmi.other_devices);
+               }
+
+               total_private += (tmi.private_clean + tmi.private_dirty);
+               total_pss += tmi.pss;
+               total_rss += tmi.rss;
+               total_graphic_3d += tmi.graphic_3d;
+               total_gem_rss += tmi.gem_rss;
+               total_gem_pss += tmi.gem_pss;
+               total_private_code += tmi.private_clean;
+               total_private_data += tmi.private_dirty;
+               total_shared_code += tmi.shared_clean;
+               total_shared_data += tmi.shared_dirty;
+               total_peak_rss += tmi.peak_rss;
+
+               total_shared_code_pss += tmi.shared_clean_pss;
+               total_shared_data_pss += tmi.shared_dirty_pss;
+       } /* end of while */
+
+       total_allocated_gem = KB(total_gem_memory());
+       fprintf(output_file,
+                       "==============================================="
+                       "===============================================\n");
+       if (verbos) {
+               fprintf(output_file,
+                               "TOTAL:      S(CODE) S(DATA) P(CODE)  P(DATA)"
+                               "    PEAK     PSS       3D    "
+                               "GEM(PSS) GEM(RSS) GEM(ALLOC) TOTAL(KB)\n");
+               fprintf(output_file,
+                       "         %8d %8d %8d %8d %8d %8d %8d"
+                       " %8d %8d %8d %8d\n",
+                       total_shared_code, total_shared_data,
+                       total_private_code, total_private_data,
+                       total_peak_rss, total_pss, total_graphic_3d,
+                       total_gem_pss, total_gem_rss,
+                       total_allocated_gem,
+                       total_pss + total_graphic_3d +
+                       total_allocated_gem);
+       } else {
+               fprintf(output_file,
+                       "TOTAL:        CODE     DATA    PEAK     PSS     "
+                       "3D    GEM(PSS) GEM(ALLOC)     TOTAL(KB)\n");
+               fprintf(output_file, "         %8d %8d %8d %8d %8d %8d %7d %8d\n",
+                       total_shared_code + total_private_code,
+                       total_shared_data + total_private_data,
+                       total_peak_rss, total_pss,
+                       total_graphic_3d, total_gem_pss,
+                       total_allocated_gem,
+                       total_pss + total_graphic_3d +
+                       total_allocated_gem);
+
+       }
+
+       if (verbos)
+               fprintf(output_file,
+                       "* S(CODE): shared clean memory, it includes"
+                       " duplicated memory\n"
+                       "* S(DATA): shared dirty memory, it includes"
+                       " duplicated memory\n"
+                       "* P(CODE): private clean memory\n"
+                       "* P(DATA): private dirty memory\n"
+                       "* PEAK: peak memory usage of S(CODE) + S(DATA)"
+                       " + P(CODE) + P(DATA)\n"
+                       "* PSS: Proportional Set Size\n"
+                       "* 3D: memory allocated by GPU driver\n"
+                       "* GEM(PSS): GEM memory devided by # of sharers\n"
+                       "* GEM(RSS): GEM memory including duplicated memory\n"
+                       "* GEM(ALLOC): sum of unique gem memory in the system\n"
+                       "* TOTAL: PSS + 3D + GEM(ALLOC) \n");
+       else
+               fprintf(output_file,
+                       "* CODE: shared and private clean memory\n"
+                       "* DATA: shared and private dirty memory\n"
+                       "* PEAK: peak memory usage of CODE + DATA\n"
+                       "* PSS: Proportional Set Size\n"
+                       "* 3D: memory allocated by GPU driver\n"
+                       "* GEM(PSS): GEM memory deviced by # of sharers\n"
+                       "* GEM(ALLOC): sum of unique GEM memory in the system\n"
+                       "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
+
+       get_tmpfs_info(output_file);
+       get_mem_info(output_file);
+
+       fclose(output_file);
+       free(glist);
+       closedir(pDir);
+       return 1;
+}
+
+static int show_map_new(int pid)
+{
+       mapinfo *milist;
+       mapinfo *mi;
+       unsigned shared_dirty = 0;
+       unsigned shared_clean = 0;
+       unsigned private_dirty = 0;
+       unsigned private_clean = 0;
+       unsigned pss = 0;
+       unsigned start = 0;
+       unsigned end = 0;
+       unsigned private_clean_total = 0;
+       unsigned private_dirty_total = 0;
+       unsigned shared_clean_total = 0;
+       unsigned shared_dirty_total = 0;
+       int duplication = 0;
+
+       milist = load_maps(pid);
+
+       if (milist == 0) {
+               fprintf(stderr, "cannot get /proc/smaps for pid %d\n", pid);
+               return 1;
+       }
+
+       if (!sum) {
+               printf(" S(CODE)  S(DATA)  P(CODE)  P(DATA)  ADDR(start-end)"
+                       "OBJECT NAME\n");
+               printf("-------- -------- -------- -------- -----------------"
+                       "------------------------------\n");
+       } else {
+               printf(" S(CODE)  S(DATA)  P(CODE)  P(DATA)  PSS\n");
+               printf("-------- -------- -------------------"
+                       "------------------\n");
+       }
+       for (mi = milist; mi; mi = mi->next) {
+               shared_clean += mi->shared_clean;
+               shared_dirty += mi->shared_dirty;
+               private_clean += mi->private_clean;
+               private_dirty += mi->private_dirty;
+               pss += mi->pss;
+
+               shared_clean_total += mi->shared_clean;
+               shared_dirty_total += mi->shared_dirty;
+               private_clean_total += mi->private_clean;
+               private_dirty_total += mi->private_dirty;
+
+               if (!duplication)
+                       start = mi->start;
+
+               if ((mi->next && !strcmp(mi->next->name, mi->name)) &&
+                   (mi->next->start == mi->end)) {
+                       duplication = 1;
+                       continue;
+               }
+               end = mi->end;
+               duplication = 0;
+
+               if (!sum) {
+                       printf("%8d %8d %8d %8d %08x-%08x %s\n",
+                              shared_clean, shared_dirty, private_clean, private_dirty,
+                              start, end, mi->name);
+               }
+               shared_clean = 0;
+               shared_dirty = 0;
+               private_clean = 0;
+               private_dirty = 0;
+       }
+       if (sum) {
+               printf("%8d %8d %8d %8d %18d\n",
+                      shared_clean_total,
+                      shared_dirty_total,
+                      private_clean_total,
+                      private_dirty_total,
+                      pss);
+       }
+
+       return 1;
+}
+
+void check_kernel_version(void)
+{
+       struct utsname buf;
+       int ret;
+
+       ret = uname(&buf);
+
+       if (!ret) {
+               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 */
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       int usage = 1;
+       sum = 0;
+
+       if (argc > 1) {
+               check_kernel_version();
+
+               if (!strcmp(argv[1], "-r")) {
+                       if (argc >= 3)
+                               show_rss(OUTPUT_FILE, argv[2]);
+                       else
+                               show_rss(OUTPUT_UART, NULL);
+                       usage = 0;
+               } else if (!strcmp(argv[1], "-s")) {
+                       sum = 1;
+                       if (argc == 3 && atoi(argv[2]) > 0) {
+                               show_map_new(atoi(argv[2]));
+                               usage = 0;
+                       }
+               } else if (!strcmp(argv[1], "-a")) {
+                       verbos = 0;
+                       show_map_all_new(OUTPUT_UART, NULL);
+                       usage = 0;
+               } else if (!strcmp(argv[1], "-v")) {
+                       verbos = 1;
+                       show_map_all_new(OUTPUT_UART, NULL);
+                       usage = 0;
+               } else if (!strcmp(argv[1], "-f")) {
+                       if (argc >= 3) {
+                               verbos = 1;
+                               show_map_all_new(OUTPUT_FILE, argv[2]);
+                               usage = 0;
+                       }
+               } else if (argc == 2 && atoi(argv[1]) > 0) {
+                       show_map_new(atoi(argv[1]));
+                       usage = 0;
+               }
+       }
+       if (usage) {
+               fprintf(stderr,
+                       "memps [-a] | [-v] | [-s] <pid> | [-f] <output file full path>\n"
+                       "        -s = sum (show only sum of each)\n"
+                       "        -f = all (show all processes via output file)\n"
+                       "        -a = all (show all processes)\n"
+                       "        -v = verbos (show all processes in detail)\n");
+       }
+
+       return 0;
+}
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..381544d
--- /dev/null
@@ -0,0 +1,233 @@
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+IF("${NETWORK_MODULE}" STREQUAL "OFF")
+       MESSAGE("DataUsage is disbaled")
+       RETURN()
+ENDIF()
+
+SET(PROJECT ${RESOURCED})
+PROJECT(${PROJECT})
+
+INCLUDE_DIRECTORIES(${INCLUDE_PUBLIC_DIR}
+               ${NETWORK_SOURCE_DIR}/include
+               ${RESOURCED_INCLUDEDIR}
+       )
+
+SET (REQUIRES_LIST dlog
+                  glib-2.0
+                  sqlite3
+                  vconf
+                  ecore
+                  edbus
+)
+
+IF("${TETHERING_FEATURE}" STREQUAL "ON")
+       SET(REQUIRES_LIST ${REQUIRES_LIST}
+                  capi-network-connection)
+ENDIF()
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs_${NETWORK} REQUIRED ${REQUIRES_LIST})
+
+FOREACH(flag ${pkgs_${NETWORK}_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+
+IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+IF("${NETWORK_SERVICE}" STREQUAL "OFF")
+       ADD_DEFINITIONS("-DNETWORK_SERVICE_OFF")
+ENDIF()
+
+#### libs ####
+
+SET(settings_HEADERS
+  ${NETWORK_SOURCE_DIR}/include/settings.h)
+
+SET(settings_SOURCES
+  ${NETWORK_SOURCE_DIR}/settings.c)
+
+ADD_LIBRARY(settings STATIC
+  ${settings_SOURCES})
+
+SET(storage_HEADERS
+  ${NETWORK_SOURCE_DIR}/include/storage.h)
+
+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)
+
+SET(quota_SOURCES
+  ${COMMON_SOURCE_DIR}/edbus-handler.c
+  ${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)
+
+SET(net-iface_HEADERS
+  ${NETWORK_SOURCE_DIR}/include/iface.h)
+
+SET(net-iface_SOURCES
+  ${NETWORK_SOURCE_DIR}/iface.c
+)
+
+SET(roaming_HEADERS
+  ${NETWORK_SOURCE_DIR}/include/roaming.h)
+
+SET(roaming_SOURCES
+  ${NETWORK_SOURCE_DIR}/dummy_roaming.c)
+
+ADD_LIBRARY(protocol-info STATIC
+  ${protocol-info_SOURCES} ${protocol-info_HEADERS})
+
+ADD_LIBRARY(storage STATIC
+  ${storage_SOURCES} ${storage_HEADERS}
+  ${quota_SOURCES} ${quota_HEADERS}
+  )
+TARGET_LINK_LIBRARIES(storage protocol-info ${pkgs_${NETWORK}_LDFLAGS})
+
+ADD_LIBRARY(app-stat STATIC
+  ${app-stat_SOURCES} ${app-stat_HEADERS})
+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})
+
+SET(net-cls_HEADERS
+  ${NETWORK_SOURCE_DIR}/include/net-cls-cgroup.h)
+
+SET(net-cls_SOURCES
+  ${NETWORK_SOURCE_DIR}/net-cls-cgroup.c)
+
+ADD_LIBRARY(net-cls STATIC
+  ${net-cls_SOURCES})
+
+#### libs ####
+
+#### lib-resourced ####
+
+SET(${PROJECT}_HEADERS
+  ${INCLUDE_PUBLIC_DIR}/data_usage.h
+  ${INCLUDE_PUBLIC_DIR}/resourced.h
+  ${INCLUDE_COMMON_DIR}/const.h
+  ${INCLUDE_COMMON_DIR}/trace.h
+  ${quota_HEADERS}
+  )
+
+SET(${PROJECT}_SOURCES
+  ${COMMON_SOURCE_DIR}/cgroup.c
+  ${COMMON_SOURCE_DIR}/appid-helper.c
+  ${COMMON_SOURCE_DIR}/file-helper.c
+  ${NETWORK_SOURCE_DIR}/foreach.c
+  ${NETWORK_SOURCE_DIR}/join.c
+  ${NETWORK_SOURCE_DIR}/options.c
+  ${NETWORK_SOURCE_DIR}/reset.c
+  ${NETWORK_SOURCE_DIR}/restriction.c
+  ${NETWORK_SOURCE_DIR}/update.c
+  ${NETWORK_SOURCE_DIR}/main.c
+  ${NETWORK_SOURCE_DIR}/nl-helper.c
+  ${NETWORK_SOURCE_DIR}/restriction-helper.c
+  ${quota_SOURCES}
+  )
+
+IF("${DATAUSAGE_TYPE}" STREQUAL "NFACCT")
+ELSE()
+  SET(${PROJECT}_SOURCES ${${PROJECT}_SOURCES}
+    ${NETWORK_SOURCE_DIR}/net-activity.c
+    ${NETWORK_SOURCE_DIR}/generic-netlink.c
+  )
+ENDIF()
+
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(shared_pkgs REQUIRED dlog
+                                      glib-2.0
+                                      sqlite3
+                                      vconf
+                                      ecore
+                                      edbus)
+
+FOREACH(flag ${shared_pkgs_CFLAGS})
+        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+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
+  ${shared_pkgs_LDFLAGS})
+
+SET_TARGET_PROPERTIES(${PROJECT}
+     PROPERTIES
+     VERSION ${FULLVER}
+     SOVERSION ${MAJORVER}
+     CLEAN_DIRECT_OUTPUT 1
+)
+
+ADD_EXECUTABLE(datausagetool ${UTILS_SOURCE_DIR}/datausage-tool.c)
+TARGET_LINK_LIBRARIES(datausagetool
+                     ${PROJECT}
+                     ${COMMON_SOURCE_DIR}/config-parser.c
+                     net-iface)
+INSTALL(TARGETS datausagetool
+    DESTINATION /usr/bin)
+
+INSTALL(TARGETS ${PROJECT} DESTINATION lib)
+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(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
new file mode 100644 (file)
index 0000000..35bd8a8
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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 app-stat.c
+ *
+ * @desc application statistics entity helper functions
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "app-stat.h"
+#include "net-cls-cgroup.h"
+#include "iface.h"
+#include "macro.h"
+#include "roaming.h"
+#include "trace.h"
+
+static void free_app(gpointer data)
+{
+       struct application_stat *app_stat = (struct application_stat *)data;
+       if (!app_stat)
+               return;
+
+       if (app_stat->application_id)
+               free(app_stat->application_id);
+
+       free(app_stat);
+}
+
+static gint compare_classid(gconstpointer a, gconstpointer b,
+       gpointer __attribute__((__unused__)) userdata)
+{
+       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;
+
+       ret = a_key->classid - b_key->classid;
+       if (!ret)
+               return ret;
+
+       ret = a_key->iftype - b_key->iftype;
+       if (!ret)
+               return ret;
+
+       return strcmp(a_key->ifname, b_key->ifname);
+}
+
+static void free_stat(gpointer data)
+{
+       free(data);
+}
+
+struct application_stat_tree *create_app_stat_tree(void)
+{
+       int ret;
+       struct application_stat_tree *app_stat_tree;
+       app_stat_tree =
+               (struct application_stat_tree *) malloc
+               (sizeof(struct application_stat_tree));
+       if (!app_stat_tree) {
+               _E("Malloc of create_app_stat_tree failed\n");
+               return NULL;
+       }
+
+       app_stat_tree->tree =
+               (GTree *)g_tree_new_full(compare_classid,
+                                                        NULL, free_stat,
+                                                        free_app);
+       app_stat_tree->last_touch_time = time(0);
+       ret = pthread_rwlock_init(&app_stat_tree->guard, NULL);
+       if (ret != 0) {
+               _E("Could not initialize tree guard %s.", strerror(ret));
+               free(app_stat_tree);
+               app_stat_tree = NULL;
+       }
+       return app_stat_tree;
+}
+
+void free_app_stat_tree(struct application_stat_tree *app_stat_tree)
+{
+       /* do not check null pointer because it makes g_tree_destroy */
+       ret_msg_if(app_stat_tree == NULL,
+               "Please provide valid app_stat_tree!");
+       g_tree_destroy((GTree *)app_stat_tree->tree);
+}
+
+void nulify_app_stat_tree(struct application_stat_tree **app_stat_tree)
+{
+       free_app_stat_tree(*app_stat_tree);
+       free(*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)
+{
+       /* Open closed principle would be better here */
+       struct application_stat *stat = (struct application_stat *)value;
+       u_int32_t classid = ((struct classid_iftype_key*)key)->classid;
+
+       /* No need to request update classid table per each app entry */
+       stat->application_id = get_app_id_by_classid(classid, false);
+       return FALSE;
+}
+
+static inline void identify_application(
+       struct application_stat_tree *app_stat_tree)
+{
+       g_tree_foreach(app_stat_tree->tree, (GTraverseFunc)set_app_id, NULL);
+}
+
+static gboolean fill_incomming(gpointer key,
+       gpointer value, gpointer data)
+{
+       struct application_stat_tree *app_tree =
+               (struct application_stat_tree *)data;
+       struct traffic_stat *in_event = (struct traffic_stat *)value;
+
+       struct application_stat *app_stat = NULL;
+       if (!is_allowed_ifindex(in_event->ifindex))
+               return FALSE;
+
+       app_stat = (struct application_stat *)
+               g_tree_lookup((GTree *)app_tree->tree, key);
+       if (app_stat)
+               app_stat->rcv_count += in_event->bytes;
+       else {
+               app_stat = g_new(struct application_stat, 1);
+               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);
+       }
+       app_stat->delta_rcv += in_event->bytes;
+
+       /*only for debug purpose*/
+       if (!app_stat->ifindex)
+               app_stat->ifindex = in_event->ifindex;
+
+       app_stat->is_roaming = get_roaming();
+       return FALSE;
+}
+
+static gboolean fill_outgoing(gpointer key,
+       gpointer value, gpointer data)
+{
+       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);
+       }
+       app_stat->delta_snd += out_event->bytes;
+
+       if (!app_stat->ifindex)
+               app_stat->ifindex = out_event->ifindex;
+
+       if (!app_stat->is_roaming)
+               app_stat->is_roaming = get_roaming();
+       return FALSE;
+}
+
+
+static void fill_result(traffic_stat_tree *tree_in,
+               traffic_stat_tree *tree_out,
+               struct application_stat_tree *result)
+{
+
+       g_tree_foreach(tree_in, (GTraverseFunc)fill_incomming, result);
+       g_tree_foreach(tree_out, (GTraverseFunc)fill_outgoing, result);
+}
+
+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);
+
+       return RESOURCED_ERROR_NONE;
+}
diff --git a/src/network/counter-process.c b/src/network/counter-process.c
new file mode 100644 (file)
index 0000000..f8abd53
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * 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 counter-process.c
+ *
+ * @desc Counter process entity
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "app-stat.h"
+#include "cgroup.h"
+#include "config.h"
+#include "const.h"
+#include "counter.h"
+#include "database.h"
+#include "datausage-common.h"
+#include "datausage-quota.h"
+#include "datausage-quota-processing.h"
+#include "datausage-restriction.h"
+#include "edbus-handler.h"
+#include "generic-netlink.h"
+#include "net-cls-cgroup.h"
+#include "nfacct-rule.h"
+#include "macro.h"
+#include "module-data.h"
+#include "notification.h"
+#include "resourced.h"
+#include "roaming.h"
+#include "storage.h"
+#include "trace.h"
+#include "transmission.h"
+#include "datausage-vconf-common.h"
+
+#include <Ecore.h>
+#include <endian.h>
+#include <glib.h>
+#include <linux/genetlink.h>
+#include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <stdbool.h>
+
+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 (?, ?, ?, ?, ?, ?, ?, ?, ?);"
+#define REMOVE_QUOTA "DELETE FROM quotas WHERE binpath=? AND iftype=? " \
+       " AND roaming=?"
+
+#define QUOTA_CEILING_VALUE 10737418220
+
+/* Warning threshold part in percent*/
+enum {
+       WARNING_THRESHOLD_DEFAULT_PART = 5,
+       WARNING_THRESHOLD_PART_10 = 10,
+       WARNING_THRESHOLD_PART_15 = 15,
+       WARNING_THRESHOLD_PART_20 = 20,
+};
+
+static sqlite3_stmt *datausage_quota_insert;
+static sqlite3_stmt *datausage_quota_remove;
+
+static bool check_net_blocked(sig_atomic_t state)
+{
+       static int net_blocked; /* counter for run only one time after blocking
+               to store gap value */
+       if (state & RESOURCED_NET_BLOCKED_STATE &&
+               net_blocked)
+               return true;
+
+       /* set net_blocked flag */
+       if (!net_blocked &&
+                       state & RESOURCED_NET_BLOCKED_STATE)
+               ++net_blocked;
+       /* reset net_blocked flag */
+       if (net_blocked &&
+               !(state & RESOURCED_NET_BLOCKED_STATE))
+               --net_blocked;
+       _D("net_blocked %d, state %d", net_blocked, state);
+       return false;
+}
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+static Eina_Bool send_counter_request(struct counter_arg *carg)
+{
+       return nfacct_send_get(carg) == RESOURCED_ERROR_NONE ?
+               ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL;
+}
+
+/* TODO exclude wlll be broken */
+static nfacct_rule_jump get_counter_jump(nfacct_rule_intend intend)
+{
+       if (intend == NFACCT_WARN)
+               return NFACCT_JUMP_ACCEPT;
+       else if (intend == NFACCT_BLOCK)
+               return NFACCT_JUMP_REJECT;
+
+       return NFACCT_JUMP_UNKNOWN;
+}
+
+static void populate_counters(char *cnt_name,
+                       struct counter_arg *carg)
+{
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       nfacct_rule_jump jump = NFACCT_JUMP_UNKNOWN;
+
+       if (!recreate_counter_by_name(cnt_name, &counter)) {
+               _E("Can't parse counter name %s", cnt_name);
+               return;
+       }
+
+       counter.carg = carg;
+       strcpy(counter.name, cnt_name);
+       jump = get_counter_jump(counter.intend);
+       _D("counter: %s, classid %u, iftype %u, iotype %d, bytes %lu", cnt_name,
+               counter.classid, counter.iftype,
+               counter.iotype);
+
+       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)
+{
+       struct traffic_stat *to_insert;
+       struct classid_iftype_key *key;
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       traffic_stat_tree *tree = NULL;
+
+       _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);
+}
+
+static int fill_counters(struct rtattr *attr_list[__NFACCT_MAX],
+               void *user_data)
+{
+       struct counter_arg *carg = user_data;
+       char *cnt_name = (char *)RTA_DATA(
+                               attr_list[NFACCT_NAME]);
+       if (carg->initiate)
+               populate_counters(cnt_name, carg);
+       else {
+               uint64_t *bytes_p = (uint64_t *)RTA_DATA(attr_list[NFACCT_BYTES]);
+               int bytes = be64toh(*bytes_p);
+               /* 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);
+       }
+
+       return 0;
+}
+
+static int post_fill_counters(void *user_data)
+{
+       struct counter_arg *carg = user_data;
+
+       if (carg->initiate)
+               carg->initiate = 0;
+
+       return 0;
+}
+
+#else
+static Eina_Bool send_counter_request(struct counter_arg *carg)
+{
+       int ret = send_command(carg->sock, carg->pid, carg->family_id_stat,
+                       TRAF_STAT_C_GET_CONN_IN);
+       ret_value_msg_if(ret < 0, ECORE_CALLBACK_RENEW,
+                       "Failed to send command to get incomming traffic");
+
+       ret = send_command(carg->sock, carg->pid, carg->family_id_stat,
+                       TRAF_STAT_C_GET_PID_OUT);
+       ret_value_msg_if(ret < 0, ECORE_CALLBACK_RENEW,
+                       "Failed to send command to get outgoing traffic");
+
+       return ECORE_CALLBACK_RENEW;
+}
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+
+static Eina_Bool _counter_func_cb(void *user_data)
+{
+       struct counter_arg *carg = (struct counter_arg *)user_data;
+
+       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
+                */
+
+               return send_counter_request(carg);
+       }
+
+       close(carg->sock);
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static dbus_bool_t deserialize_restriction(
+       DBusMessage *msg, char **appid, resourced_net_restrictions *rest,
+       enum traffic_restriction_type *rst_type)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       int ret = dbus_message_get_args(
+               msg, &err,
+               DBUS_TYPE_STRING, appid,
+               DBUS_TYPE_INT32, rst_type,
+               DBUS_TYPE_INT32, &(rest->rs_type),
+               DBUS_TYPE_INT32, &(rest->iftype),
+               DBUS_TYPE_INT32, &(rest->send_limit),
+               DBUS_TYPE_INT32, &(rest->rcv_limit),
+               DBUS_TYPE_INT32, &(rest->snd_warning_limit),
+               DBUS_TYPE_INT32, &(rest->rcv_warning_limit),
+               DBUS_TYPE_INT32, &(rest->roaming),
+               DBUS_TYPE_INVALID);
+
+       if (ret == FALSE) {
+               _E("Can't deserialize quota! [%s:%s]\n",
+               err.name, err.message);
+       }
+
+       dbus_error_free(&err);
+
+       return ret;
+}
+
+static DBusMessage *edbus_process_restriction(E_DBus_Object *obj,
+                                             DBusMessage *msg)
+{
+       DBusMessageIter iter;
+       DBusMessage *reply;
+       int ret;
+       resourced_ret_c dbus_ret = RESOURCED_ERROR_NONE;
+       char *appid = NULL;
+       resourced_net_restrictions rest;
+       enum traffic_restriction_type rst_type;
+
+       ret = dbus_message_is_method_call(
+           msg, RESOURCED_INTERFACE_NETWORK,
+           RESOURCED_NETWORK_PROCESS_RESTRICTION);
+
+       if (ret == FALSE)
+               return dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD,
+                                             "Method is not supported");
+
+       ret = deserialize_restriction(msg, &appid, &rest, &rst_type);
+
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(reply, &iter);
+       if (ret == FALSE) {
+               dbus_ret = RESOURCED_ERROR_FAIL;
+               goto out;
+       }
+
+       dbus_ret = proc_keep_restriction(appid, NONE_QUOTA_ID, &rest,
+                                            rst_type);
+out:
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &dbus_ret);
+
+       return reply;
+}
+
+static DBusMessage *edbus_update_counters(E_DBus_Object *obj, DBusMessage *msg)
+{
+       DBusMessage *reply;
+       struct shared_modules_data *m_data = get_shared_modules_data();
+
+       if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
+                                       RESOURCED_NETWORK_UPDATE) == 0)
+               return dbus_message_new_error(msg, DBUS_ERROR_UNKNOWN_METHOD,
+                                             "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;
+
+               /* postpone periodic update on one minute */
+               reschedule_count_timer(m_data->carg, COUNTER_UPDATE_PERIOD);
+               _counter_func_cb(m_data->carg);
+       }
+
+       reply = dbus_message_new_method_return(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)
+               return WARNING_THRESHOLD_PART_20;
+
+       if (time_period < RESOURCED_PERIOD_WEEK)
+               return WARNING_THRESHOLD_PART_15;
+
+       if (time_period < RESOURCED_PERIOD_MONTH)
+               return WARNING_THRESHOLD_PART_10;
+
+       return WARNING_THRESHOLD_DEFAULT_PART;
+}
+
+static inline int64_t get_quota_ceiling(const int64_t quota)
+{
+       return quota >= QUOTA_CEILING_VALUE ? QUOTA_CEILING_VALUE :
+               quota;
+}
+
+static inline int _evaluate_warning_threshold(const int64_t quota,
+       const int time_period, const int user_threshold)
+{
+       int threshold_part = WARNING_THRESHOLD_DEFAULT_PART;
+
+       if (user_threshold != WARNING_THRESHOLD_DEFAULT)
+               return user_threshold;
+
+       threshold_part = _get_threshold_part(time_period);
+
+       return (get_quota_ceiling(quota) / 100 ) * threshold_part;
+}
+
+static dbus_bool_t deserialize_quota(
+       DBusMessage *msg, char **appid,
+       struct serialization_quota *quota)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       int ret = dbus_message_get_args(
+               msg, &err,
+               DBUS_TYPE_STRING, appid,
+               DBUS_TYPE_INT32, &quota->time_period,
+               DBUS_TYPE_UINT64, &quota->snd_quota,
+               DBUS_TYPE_UINT64, &quota->rcv_quota,
+               DBUS_TYPE_INT32, &quota->snd_warning_threshold,
+               DBUS_TYPE_INT32, &quota->rcv_warning_threshold,
+               DBUS_TYPE_INT32, &quota->quota_type,
+               DBUS_TYPE_INT32, &quota->iftype,
+               DBUS_TYPE_INT32, &quota->start_time,
+               DBUS_TYPE_INT32, &quota->roaming_type,
+               DBUS_TYPE_INVALID);
+       if (ret == FALSE) {
+               _E("Can't deserialize set quota message ![%s:%s]\n",
+               err.name, err.message);
+       }
+
+       dbus_error_free(&err);
+
+       quota->iftype = (quota->iftype == RESOURCED_IFACE_UNKNOWN) ?
+                       RESOURCED_IFACE_ALL : quota->iftype;
+
+       quota->snd_warning_threshold = _evaluate_warning_threshold(
+               quota->snd_quota, quota->time_period,
+               quota->snd_warning_threshold);
+       quota->rcv_warning_threshold = _evaluate_warning_threshold(
+               quota->rcv_quota, quota->time_period,
+               quota->rcv_warning_threshold);
+
+return ret;
+}
+
+static dbus_bool_t deserialize_remove_quota(
+       DBusMessage *msg, char **appid,
+       resourced_iface_type *iftype, resourced_roaming_type *roaming)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       int ret = dbus_message_get_args(
+               msg, &err,
+               DBUS_TYPE_STRING, appid,
+               DBUS_TYPE_INT32, iftype,
+               DBUS_TYPE_INT32, roaming,
+               DBUS_TYPE_INVALID);
+       if (ret == FALSE) {
+               _E("Can't deserialize remove quota message! [%s:%s]\n",
+               err.name, err.message);
+       }
+
+       dbus_error_free(&err);
+
+       return ret;
+}
+
+static DBusMessage *edbus_join_net_stat(E_DBus_Object *obj, DBusMessage *msg)
+{
+       char *app_id = NULL;
+       int pid = 0;
+       resourced_ret_c ret = RESOURCED_ERROR_NONE;
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusError err;
+
+       dbus_error_init(&err);
+
+       if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
+                               RESOURCED_NETWORK_JOIN_NET_STAT) == 0) {
+               ret = RESOURCED_ERROR_INVALID_PARAMETER;
+               goto join_net_out;
+       }
+
+       ret = dbus_message_get_args(
+               msg, &err,
+               DBUS_TYPE_STRING, &app_id,
+               DBUS_TYPE_INT32, &pid,
+               DBUS_TYPE_INVALID);
+       if (ret == FALSE) {
+               _E("Can't deserialize join netstat message! [%s:%s]\n",
+               err.name, err.message);
+               ret = RESOURCED_ERROR_INVALID_PARAMETER;
+               goto join_net_out;
+       }
+
+       ret = join_net_cls(app_id, pid);
+
+join_net_out:
+       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);
+       return reply;
+}
+
+static int init_datausage_quota_remove(sqlite3 *db)
+{
+       int rc;
+
+       if (datausage_quota_remove)
+               return SQLITE_OK;
+
+        rc = sqlite3_prepare_v2(db, REMOVE_QUOTA, -1,
+                       &datausage_quota_remove, NULL);
+       if (rc != SQLITE_OK) {
+               _E("can not prepare datausage_quota_remove");
+               datausage_quota_remove = NULL;
+               sqlite3_finalize(datausage_quota_remove);
+               return rc;
+       }
+
+       return rc;
+}
+
+static resourced_ret_c remove_quota(const char *app_id,
+       resourced_iface_type iftype, resourced_roaming_type roaming)
+{
+       resourced_ret_c error_code = RESOURCED_ERROR_NONE;
+       libresourced_db_initialize_once();
+
+       if (init_datausage_quota_remove(resourced_get_database()) != SQLITE_OK) {
+               _D("Failed to initialize data usage quota statements: %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+
+       if (sqlite3_bind_text(datausage_quota_remove, 1, app_id, -1, SQLITE_STATIC) !=
+           SQLITE_OK) {
+               _SE("Can not bind app_id: %s for preparing statement",
+                  app_id);
+               error_code =  RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int(datausage_quota_remove, 2, iftype)
+           != SQLITE_OK) {
+               _E("Can not bind iftype:%d for preparing statement",
+                       iftype);
+               error_code =  RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int(datausage_quota_remove, 3, roaming)
+           != SQLITE_OK) {
+               _E("Can not bind iftype:%d for preparing statement",
+                       roaming);
+               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);
+
+       _SD("quota for app %s removed", app_id);
+
+out:
+       sqlite3_reset(datausage_quota_remove);
+       return error_code;
+}
+
+static DBusMessage *edbus_remove_quota(E_DBus_Object *obj, DBusMessage *msg)
+{
+       char *app_id = NULL;
+       resourced_iface_type iftype;
+       resourced_ret_c ret = RESOURCED_ERROR_NONE;
+       resourced_roaming_type roaming;
+       DBusMessage *reply;
+       DBusMessageIter iter;
+
+       if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
+                               RESOURCED_NETWORK_REMOVE_QUOTA) == 0) {
+               ret = RESOURCED_ERROR_INVALID_PARAMETER;
+               goto remove_out;
+       }
+
+       if (deserialize_remove_quota(msg, &app_id, &iftype, &roaming)
+                            == 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);
+
+remove_out:
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+       return reply;
+}
+
+static int init_datausage_quota_insert(sqlite3 *db)
+{
+       int rc;
+
+       if (datausage_quota_insert)
+               return SQLITE_OK;
+
+       rc = sqlite3_prepare_v2(db, INSERT_QUERY,
+                                   -1, &datausage_quota_insert, NULL);
+
+       if (rc != SQLITE_OK) {
+               _E("can not prepare datausage_quota_insert");
+               datausage_quota_insert = NULL;
+               sqlite3_finalize(datausage_quota_insert);
+       }
+
+       return rc;
+}
+
+static resourced_ret_c store_quota(const char *app_id,
+       const struct serialization_quota *quota)
+{
+       resourced_ret_c error_code = RESOURCED_ERROR_NONE;
+
+       libresourced_db_initialize_once();
+
+       if (init_datausage_quota_insert(resourced_get_database()) != SQLITE_OK) {
+               _D("Failed to initialize data usage quota statements: %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+
+       if (sqlite3_bind_text(datausage_quota_insert, 1, app_id, -1,
+               SQLITE_STATIC) != 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;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(datausage_quota_insert, 2,
+               quota->snd_quota) != SQLITE_OK) {
+               _E("Can not bind snd_quota: %lld for preparing statement",
+                       quota->snd_quota);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(datausage_quota_insert, 3,
+               quota->rcv_quota) != SQLITE_OK) {
+               _E("Can not bind rcv_quota: %lld for preparing statement",
+                       quota->rcv_quota);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(datausage_quota_insert, 4,
+               quota->snd_warning_threshold) != SQLITE_OK) {
+               _E("Can not bind snd_warning_threshold: %lld for preparing statement",
+                       quota->snd_warning_threshold);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(datausage_quota_insert, 5,
+               quota->rcv_warning_threshold) != SQLITE_OK) {
+               _E("Can not bind rcv_warning_threshold: %lld for preparing statement",
+                       quota->rcv_warning_threshold);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(datausage_quota_insert, 6,
+               quota->time_period) != SQLITE_OK) {
+               _E("Can not bind time_period: %d for preparing statement",
+                       quota->time_period);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int(datausage_quota_insert, 7,
+               quota->start_time) != SQLITE_OK) {
+               _E("Can not bind start_time: %d for preparing statement",
+                       quota->start_time);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int(datausage_quota_insert, 8,
+               quota->iftype) != SQLITE_OK) {
+               _E("Can not bind iftype: %d for preparing statement",
+                       quota->iftype);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       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);
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_step(datausage_quota_insert) != SQLITE_DONE) {
+               _E("Failed to record quota %s.",
+                       sqlite3_errmsg(resourced_get_database()));
+               error_code = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+out:
+       sqlite3_reset(datausage_quota_insert);
+       return error_code;
+}
+
+static DBusMessage *edbus_create_quota(E_DBus_Object *obj, DBusMessage *msg)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter;
+
+       char *app_id = NULL;
+       struct serialization_quota quota;
+       struct shared_modules_data *m_data = get_shared_modules_data();
+       struct counter_arg *carg;
+       resourced_ret_c ret = RESOURCED_ERROR_NONE;
+
+       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 update_out;
+       }
+
+       carg = m_data->carg;
+
+       if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
+                                       RESOURCED_NETWORK_CREATE_QUOTA) == 0) {
+               _E("Invalid DBUS argument");
+               ret = RESOURCED_ERROR_INVALID_PARAMETER;
+               goto update_out;
+       }
+
+       deserialize_quota(msg, &app_id, &quota);
+       ret = store_quota(app_id, &quota);
+       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);
+
+       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;
+       reschedule_count_timer(carg, 0);
+       _SD("Datausage quota changed");
+
+update_out:
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
+       return reply;
+}
+
+struct get_stats_context {
+       DBusMessage *reply;
+       DBusMessage *msg;
+       int info_count;
+       GSList *infos;
+       DBusMessageIter iter;
+};
+
+static resourced_cb_ret answer_get_stat(const data_usage_info *info,
+                                              void *user_data)
+{
+       struct get_stats_context *ctx = (struct get_stats_context *)user_data;
+       data_usage_info *insert = (data_usage_info *)malloc(sizeof(data_usage_info));
+
+       ret_value_msg_if(insert == NULL, RESOURCED_CANCEL, "Can't allocate memory!");
+       memcpy(insert, info, sizeof(data_usage_info));
+       if (info->app_id) {
+               int app_id_len = strlen(info->app_id) + 1;
+               insert->app_id = (char *)malloc(app_id_len);
+               if (!insert->app_id) {
+                       free(insert);
+                       _E("Malloc of answer_get_stat failed\n");
+                       return RESOURCED_CANCEL;
+               }
+
+               strncpy((char *)insert->app_id, info->app_id, app_id_len);
+       }
+       ctx->infos = g_slist_append(ctx->infos, insert);
+       return RESOURCED_CONTINUE;
+}
+
+static void prepare_response(struct get_stats_context *ctx)
+{
+       GSList *iter;
+       data_usage_info *info;
+       DBusMessageIter arr;
+
+       ctx->reply = dbus_message_new_method_return(ctx->msg);
+       dbus_message_iter_init_append(ctx->reply, &ctx->iter);
+       dbus_message_iter_open_container(&ctx->iter, DBUS_TYPE_ARRAY, "(siiiiiii)", &arr);
+
+       gslist_for_each_item(iter, ctx->infos) {
+               info = (data_usage_info *)iter->data;
+
+               DBusMessageIter sub;
+
+               dbus_message_iter_open_container(&arr, DBUS_TYPE_STRUCT, NULL, &sub);
+               if (info->app_id == NULL)
+                       dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING,
+                               &null_str);
+               else
+                       dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING,
+                               &info->app_id);
+               dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &info->iftype);
+               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);
+               /* outgoing bytes */
+               dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &info->foreground.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);
+
+               dbus_message_iter_close_container(&arr, &sub);
+       }
+
+       dbus_message_iter_close_container(&ctx->iter, &arr);
+       g_slist_free_full(ctx->infos, free);
+}
+
+static void deserialize_rule(DBusMessage *msg, data_usage_selection_rule *rule, char **app_id)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       int ret = dbus_message_get_args(
+               msg, &err,
+               DBUS_TYPE_STRING, app_id,
+               DBUS_TYPE_INT32, &rule->from,
+               DBUS_TYPE_INT32, &rule->to,
+               DBUS_TYPE_INT32, &rule->iftype,
+               DBUS_TYPE_INT32, &rule->granularity,
+               DBUS_TYPE_INVALID);
+
+       if (ret == FALSE) {
+               _E("Can't deserialize quota! [%s:%s]\n",
+                       err.name, err.message);
+       }
+
+       if (app_id && !strcmp(*app_id, null_str))
+               *app_id = NULL;
+       dbus_error_free(&err);
+}
+
+static DBusMessage *edbus_get_stats(E_DBus_Object *obj, DBusMessage *msg)
+{
+       data_usage_selection_rule rule;
+       char *app_id = NULL;
+       resourced_ret_c ret;
+       struct get_stats_context ctx;
+       ctx.infos = NULL;
+
+       if (dbus_message_is_method_call(msg, RESOURCED_INTERFACE_NETWORK,
+                                       RESOURCED_NETWORK_GET_STATS) == 0) {
+               ret = RESOURCED_ERROR_INVALID_PARAMETER;
+               goto update_out;
+       }
+
+       _SD("Datausage get stats");
+       ctx.msg = msg;
+       deserialize_rule(msg, &rule, &app_id);
+       if (app_id)
+               ret = data_usage_details_foreach(app_id, &rule, answer_get_stat,
+                       &ctx);
+       else
+               ret = data_usage_foreach(&rule, answer_get_stat, &ctx);
+
+       prepare_response(&ctx);
+       return ctx.reply;
+
+update_out:
+       ctx.reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(ctx.reply, &ctx.iter);
+       dbus_message_iter_append_basic(&ctx.iter, DBUS_TYPE_INT32, &ret);
+       return ctx.reply;
+}
+
+struct nl_family_params {
+       struct genl *ans;
+       struct counter_arg *carg;
+};
+
+typedef struct {
+       struct nl_family_params params;
+       void (*process)(struct nl_family_params *params);
+} nl_serialization_command;
+
+static inline char *_get_public_appid(const uint32_t classid)
+{
+       char *appid;
+
+       /* 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;
+
+       appid = get_app_id_by_classid(classid, true);
+       return !appid ? UNKNOWN_APP : appid;
+}
+
+static bool need_flush_immediatelly(sig_atomic_t state)
+{
+       return state & RESOURCED_FORCIBLY_FLUSH_STATE ||
+               state & RESOURCED_FORCIBLY_QUIT_STATE;
+}
+
+static Eina_Bool _store_and_free_result_cb(void *user_data)
+{
+       struct counter_arg *arg = (struct counter_arg *)user_data;
+
+       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)) {
+               /*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 (broadcast_edbus_signal(
+                                   RESOURCED_PATH_NETWORK,
+                                   RESOURCED_INTERFACE_NETWORK,
+                                   RESOURCED_NETWORK_UPDATE_FINISH,
+                                   DBUS_TYPE_INVALID, NULL))
+                               _E("Failed to send DBUS message\n");
+               }
+       }
+
+       arg->store_result_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static void _store_and_free_result(struct counter_arg *arg)
+{
+       if (!arg->store_result_timer)
+               arg->store_result_timer = ecore_timer_add(STORE_DELAY_INTERVAL,
+                                          _store_and_free_result_cb, arg);
+}
+
+static void _process_network_counter(struct nl_family_params *params)
+{
+       resourced_ret_c ret;
+       struct netlink_serialization_params ser_params = {
+               .carg = params->carg,
+               .ans = params->ans,
+#ifdef CONFIG_DATAUSAGE_NFACCT
+               .eval_attr = fill_counters,
+               .post_eval_attr = post_fill_counters,
+#endif
+       };
+
+       netlink_serialization_command *netlink =
+               netlink_create_command(&ser_params);
+
+       if (!netlink) {
+               _E("Can not create command");
+               return;
+       }
+
+       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!");
+               return;
+       }
+       ret = process_quota(params->carg->result, params->carg->opts);
+       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);
+}
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+static resourced_ret_c choose_netlink_process(struct genl *ans, nl_serialization_command *command,
+       struct counter_arg *carg)
+{
+       command->process = _process_network_counter;
+       return RESOURCED_ERROR_NONE;
+}
+#else
+
+static void _process_restriction(struct nl_family_params *cmd)
+{
+       struct traffic_restriction restriction = {0,};
+       uint8_t notification_type = RESTRICTION_NOTI_C_UNSPEC;
+       char *app_id = NULL;
+       resourced_iface_type iftype;
+       resourced_restriction_info rst_info = {0,};
+       resourced_ret_c ret;
+
+       _D("Restriction notification");
+
+       if (process_netlink_restriction_msg(cmd->ans, &restriction,
+           &notification_type) !=
+           RESOURCED_ERROR_NONE) {
+               _E("Failed to process netlink restriction.");
+               return;
+       }
+
+       app_id = _get_public_appid(restriction.sk_classid);
+       iftype = get_iftype(restriction.ifindex);
+
+       ret = get_restriction_info(app_id, iftype, &rst_info);
+       ret_msg_if(ret != RESOURCED_ERROR_NONE,
+               "Failed to get restriction info!");
+
+       if (notification_type == RESTRICTION_NOTI_C_ACTIVE) {
+               if (rst_info.quota_id != NONE_QUOTA_ID)
+                       send_restriction_notification(app_id);
+               update_restriction_db(app_id, iftype, 0, 0,
+                                     RESOURCED_RESTRICTION_ACTIVATED,
+               rst_info.quota_id, rst_info.roaming);
+       } 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);
+       } else
+               _E("Unkown restriction notification type");
+}
+
+static resourced_ret_c choose_netlink_process(struct genl *ans,
+       nl_serialization_command *command, struct counter_arg *carg)
+{
+       int family = netlink_get_family(ans);
+
+       if (family == carg->family_id_restriction)
+               command->process = _process_restriction;
+       else if (family == carg->family_id_stat)
+               command->process = _process_network_counter;
+       else {
+               _E("General netlink family %d unsupported!", family);
+               return RESOURCED_ERROR_NO_DATA;
+       }
+       return RESOURCED_ERROR_NONE;
+}
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+
+static nl_serialization_command *choose_handler(struct genl *ans,
+       struct counter_arg *carg)
+{
+       static nl_serialization_command command;
+       resourced_ret_c ret;
+
+       if (!ans || !carg) {
+               _E("Please provide valid pointer!");
+               return NULL;
+       }
+
+       if (!command.params.carg)
+               command.params.carg = carg;
+       command.params.ans = ans;
+
+       ret = choose_netlink_process(ans, &command, carg);
+       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, NULL,
+               "Could not choose proper netlink process function! \n");
+
+       return &command;
+}
+
+static Eina_Bool _answer_func_cb(void *user_data, Ecore_Fd_Handler *fd_handler)
+{
+       struct counter_arg *carg = (struct counter_arg *)user_data;
+       struct genl ans;
+       nl_serialization_command *netlink_handler = NULL;
+       int ret;
+
+       ret = read_netlink(carg->sock, &ans, sizeof(struct genl));
+       if (ret == 0)
+               goto out;
+       carg->ans_len = ret;
+       netlink_handler = choose_handler(&ans, carg);
+
+       if (!netlink_handler)
+               goto out;
+
+       netlink_handler->process(&(netlink_handler->params));
+
+out:
+       return ECORE_CALLBACK_RENEW;
+}
+
+static const struct edbus_method edbus_methods[] = {
+       { RESOURCED_NETWORK_UPDATE, NULL, NULL, edbus_update_counters },
+       { RESOURCED_NETWORK_PROCESS_RESTRICTION, NULL, NULL,
+         edbus_process_restriction },
+       { RESOURCED_NETWORK_CREATE_QUOTA, NULL, NULL, edbus_create_quota },
+       { RESOURCED_NETWORK_REMOVE_QUOTA, NULL, NULL, edbus_remove_quota },
+       { RESOURCED_NETWORK_JOIN_NET_STAT, NULL, NULL, edbus_join_net_stat },
+       { RESOURCED_NETWORK_GET_STATS, "siiii", "a(siiiiiii)", edbus_get_stats },
+};
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+int init_sock(struct counter_arg *carg)
+{
+       carg->sock = create_netlink(NETLINK_NETFILTER, 0);
+       return carg->sock != 0 ? RESOURCED_ERROR_NONE :
+               RESOURCED_ERROR_FAIL;
+}
+#else
+int init_sock(struct counter_arg *carg)
+{
+       int error = RESOURCED_ERROR_NONE;
+       carg->sock = create_netlink(NETLINK_GENERIC, 0);
+
+       ret_value_msg_if(carg->sock < 0, RESOURCED_ERROR_FAIL,
+               "Failed to create and bind netlink socket.");
+
+       carg->family_id_stat = get_family_id(carg->sock,
+               carg->pid, "TRAF_STAT");
+       if (carg->family_id_stat == 0) {
+               _E("Failed to get family id for TRAF_STAT.");
+               error = RESOURCED_ERROR_FAIL;
+               goto release_sock;
+       }
+
+       carg->family_id_restriction = get_family_id(carg->sock,
+               carg->pid, "REST_NOTI");
+
+       if (carg->family_id_restriction ==  0) {
+               _E("Failed to get family id for REST_NOTI.");
+               error = RESOURCED_ERROR_FAIL;
+               goto release_sock;
+       }
+       /*thereafter we'll be able to receive message from server */
+       send_start(carg->sock, carg->pid, carg->family_id_stat);
+
+       return RESOURCED_ERROR_NONE;
+release_sock:
+       close(carg->sock);
+       return error;
+}
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+
+
+int resourced_init_counter_func(struct counter_arg *carg)
+{
+       int error = 0;
+
+       if (!carg) {
+               _E("Please provide valid argument for counting routine.");
+               error = RESOURCED_ERROR_INVALID_PARAMETER;
+               return error;
+       }
+
+       error = init_sock(carg);
+       ret_value_msg_if(error != RESOURCED_ERROR_NONE, RESOURCED_ERROR_FAIL,
+                        "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 */
+
+       init_iftype();
+
+       error = edbus_add_methods(RESOURCED_PATH_NETWORK, edbus_methods,
+                         ARRAY_SIZE(edbus_methods));
+
+       if (error != RESOURCED_ERROR_NONE)
+               _E("DBus method registration for %s is failed",
+                       RESOURCED_PATH_NETWORK);
+
+       _counter_func_cb(carg);
+
+       carg->ecore_timer = ecore_timer_add(carg->opts->update_period,
+                                          _counter_func_cb, carg);
+
+       ret_value_msg_if(carg->ecore_timer == 0, RESOURCED_ERROR_FAIL,
+                        "carg_timer is null, can't work! update period: %d",
+                        carg->opts->update_period);
+
+       carg->ecore_fd_handler = ecore_main_fd_handler_add(
+               carg->sock, ECORE_FD_READ, _answer_func_cb, carg, NULL, NULL);
+       _D("ecore_carg_handler = %p", carg->ecore_fd_handler);
+
+       return error;
+}
+
+static void finalize_quota_insert(void)
+{
+       if (datausage_quota_insert) {
+               sqlite3_finalize(datausage_quota_insert);
+               datausage_quota_insert = NULL;
+       }
+}
+
+static void finalize_quota_remove(void)
+{
+       if (datausage_quota_remove) {
+               sqlite3_finalize(datausage_quota_remove);
+               datausage_quota_remove = NULL;
+       }
+}
+
+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);
+       finalize_quota_insert();
+       finalize_quota_remove();
+}
diff --git a/src/network/counter.c b/src/network/counter.c
new file mode 100644 (file)
index 0000000..fd436a3
--- /dev/null
@@ -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: counter.c
+ *  @desc Entity for working with datausage counter.
+ *
+ */
+
+#include "app-stat.h"
+#include "counter.h"
+#include "macro.h"
+#include "trace.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+struct counter_arg *init_counter_arg(struct daemon_opts *opts)
+{
+       struct counter_arg *result =
+               (struct counter_arg *)calloc(1, sizeof(struct counter_arg));
+
+       ret_value_msg_if(result == NULL, NULL, "Not enough memory\n");
+#ifndef CONFIG_DATAUSAGE_NFACCT
+       result->pid = getpid();
+#endif
+       result->opts = opts;
+       return result;
+}
+
+void finalize_carg(struct counter_arg *carg)
+{
+       free(carg);
+}
+
+void reschedule_count_timer(const struct counter_arg *carg, const double delay)
+{
+       ret_msg_if(!carg || !carg->ecore_timer,
+                        "Invalid counter argument or carg_timer is null\n");
+       ecore_timer_delay(carg->ecore_timer,
+                         delay - ecore_timer_pending_get(carg->ecore_timer));
+}
diff --git a/src/network/daemon-options.c b/src/network/daemon-options.c
new file mode 100644 (file)
index 0000000..a610026
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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: daemon-options.c
+ *
+ *  @desc Entity for working with daemon options
+ *
+ */
+
+#include "daemon-options.h"
+#include "macro.h"
+#include "resourced.h"
+#include "settings.h"
+#include "trace.h"
+
+void load_daemon_opts(struct daemon_opts *daemon_options)
+{
+       resourced_options options = { 0 };
+
+       ret_msg_if(daemon_options == NULL,
+                        "Invalid daemon options argument\n");
+       load_options(&options);
+       daemon_options->datacall_logging = options.datacall_logging;
+       daemon_options->update_period = options.datausage_timer;
+}
diff --git a/src/network/datausage-common.c b/src/network/datausage-common.c
new file mode 100644 (file)
index 0000000..697d5a6
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ * 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 datausage.c
+ *
+ * @desc Datausage module
+ *
+ */
+
+#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 "generic-netlink.h"
+#include "net-cls-cgroup.h"
+#include "nl-helper.h"
+#include "notifier.h"
+#include "notification.h" /* for sending datausage dbus notification */
+#include "daemon-options.h"
+#include "datausage-common.h"
+#include "datausage-quota.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 "storage.h"
+#include "trace.h"
+
+#include <linux/rtnetlink.h>
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+
+
+struct make_rule_context {
+       struct counter_arg *carg;
+       struct nfacct_rule *counter;
+};
+
+struct nfacct_key {
+       u_int32_t classid;
+       resourced_iface_type iftype;
+       nfacct_rule_direction iotype;
+       char ifname[MAX_NAME_LENGTH];
+};
+
+enum nfacct_state {
+       NFACCT_STATE_ACTIVE,    /* kernel counter is applied */
+       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 */
+};
+
+struct nfacct_value {
+       pid_t pid;
+       enum nfacct_state state;
+};
+
+static nfacct_rule_jump get_jump_by_intend(struct nfacct_rule *counter)
+{
+       if (counter->intend == NFACCT_WARN)
+               return NFACCT_JUMP_ACCEPT;
+       else if (counter->intend == NFACCT_BLOCK)
+               return NFACCT_JUMP_REJECT;
+
+       return NFACCT_JUMP_UNKNOWN;
+}
+
+static resourced_ret_c add_iptables_in(struct nfacct_rule *counter)
+{
+       return produce_net_rule(counter, 0, 0,
+               NFACCT_ACTION_INSERT, get_jump_by_intend(counter),
+               NFACCT_COUNTER_IN);
+}
+
+static resourced_ret_c add_iptables_out(struct nfacct_rule *counter)
+{
+       return produce_net_rule(counter, 0, 0,
+               NFACCT_ACTION_INSERT, get_jump_by_intend(counter),
+               NFACCT_COUNTER_OUT);
+}
+
+static resourced_ret_c del_iptables_in(struct nfacct_rule *counter)
+{
+       return produce_net_rule(counter, 0, 0,
+               NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
+               NFACCT_COUNTER_IN);
+}
+
+static resourced_ret_c del_iptables_out(struct nfacct_rule *counter)
+{
+       return produce_net_rule(counter, 0, 0,
+               NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
+               NFACCT_COUNTER_OUT);
+}
+
+#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;
+       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.");
+       return ret;
+}
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+
+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;
+
+       if (iftype == RESOURCED_IFACE_UNKNOWN)
+               return FALSE;
+
+       nf_key.classid = counter->classid;
+       nf_key.iotype = counter->iotype;
+       counter->iftype = nf_key.iftype = iftype;
+
+       generate_counter_name(counter);
+       counter->iptables_rule(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
+
+       return FALSE;
+}
+
+static void remove_nfacct_counters_for_all_iface(u_int32_t classid, struct counter_arg *carg)
+{
+       struct nfacct_rule counter = {
+               .classid = classid,
+               .iotype = NFACCT_COUNTER_IN,
+               .iptables_rule = del_iptables_in,
+               .carg = carg,
+               /* .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);
+       /* 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);
+}
+
+struct match_nftree_context
+{
+       u_int32_t classid;
+       pid_t pid;
+};
+
+static gboolean match_pid(gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       struct match_nftree_context *ctx = (struct match_nftree_context *)data;
+       struct nfacct_value *nf_value = (struct nfacct_value *)value;
+       struct nfacct_key *nf_key = (struct nfacct_key *)key;
+       if (nf_value->pid == ctx->pid) {
+               ctx->classid = nf_key->classid;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static u_int32_t get_classid_by_pid(struct counter_arg *carg, const pid_t pid)
+{
+       struct match_nftree_context ctx = {
+               .pid = pid,
+               .classid = RESOURCED_UNKNOWN_CLASSID,
+       };
+       g_tree_foreach(carg->nf_cntrs, match_pid, &ctx);
+       return ctx.classid;
+}
+
+static int app_terminate_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;
+       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!");
+
+       remove_nfacct_counters_for_all_iface(classid, carg);
+       return RESOURCED_ERROR_NONE;
+}
+
+static gboolean populate_classid_tree(gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       GTree *classid_tree = (GTree *)data;
+       struct nfacct_key *nf_key = (struct nfacct_key *)key;
+       struct nfacct_value *nf_value = (struct nfacct_value *)value;
+
+       if (nf_value->state == NFACCT_STATE_ACTIVE)
+               g_tree_insert(classid_tree, (const gpointer)nf_key->classid, NULL);
+       return FALSE;
+}
+
+static gboolean remove_each_counter_by_classid(gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       u_int32_t classid = (u_int32_t)key;
+       struct counter_arg *carg = (struct counter_arg *)data;
+       remove_nfacct_counters_for_all_iface(classid, carg);
+       return FALSE;
+}
+
+static gint pointer_compare(gconstpointer a, gconstpointer b)
+{
+       return a - b;
+}
+
+static int add_one_tizen_os_counter(
+       gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       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;
+
+       if (iftype <= RESOURCED_IFACE_UNKNOWN ||
+               iftype >= RESOURCED_IFACE_LAST_ELEM)
+               return FALSE;
+
+       counter.iotype = NFACCT_COUNTER_IN;
+       counter.iftype = iftype;
+       counter.carg = carg;
+       generate_counter_name(&counter);
+       add_iptables_in(&counter);
+       counter.iotype = NFACCT_COUNTER_OUT;
+       generate_counter_name(&counter);
+       add_iptables_out(&counter);
+       return FALSE;
+}
+
+static void add_tizen_os_counters(struct counter_arg *carg) {
+
+       for_each_ifindex((ifindex_iterator)add_one_tizen_os_counter, NULL, carg);
+}
+
+static void reload_all_nf_counters(struct counter_arg *carg)
+{
+       add_tizen_os_counters(carg);
+       /* it can be done by following ways:
+        * 1. just by reading existing net_cls cgroups, looks not robust because
+        *      in this case we are getting network interface type from runtime, and
+        *      it could be changed since the resourced was stopped. And it doesn't
+        *      reflect counter state
+        * 2. By reading from iptables rules. We don't have C code for retriving
+        *      it from kernel unless to use iptables cmd output, but it's not
+        *       robust and not performance effective
+        * 3. Just by obtaining nfacct counters. We could do it without command
+        *      line tool. It reflects current counter state, but not,
+        *       iptables rules
+        */
+       carg->initiate = 1;
+       nfacct_send_initiate(carg);
+}
+
+static void remove_whole_nf_counters(struct counter_arg *carg)
+{
+       GTree *classid_tree = g_tree_new(pointer_compare);; /* tree instead of array for avoiding
+       duplication, manual sort and binary search in case of array */
+       ret_msg_if(carg == NULL,
+               "Cant' get counter arg!");
+
+       /* fill classid list, due we couldn't iterate on tree and
+        * remove elements from it */
+       g_tree_foreach(carg->nf_cntrs, populate_classid_tree, classid_tree);
+       g_tree_foreach(classid_tree, remove_each_counter_by_classid, carg);
+
+       g_tree_destroy(carg->nf_cntrs);
+       g_tree_destroy(classid_tree);
+}
+
+/* notification section */
+/*
+ * TODO use following constant from kernel header
+ * nfacct/include/linux/netfilter/nfnetlink.h
+ * */
+#ifndef NFNLGRP_ACCT_QUOTA
+#define NFNLGRP_ACCT_QUOTA 8
+#endif
+#ifndef SOL_NETLINK
+#define SOL_NETLINK    270
+#endif
+
+static inline char *get_public_appid(const uint32_t classid)
+{
+       char *appid;
+
+       /* 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;
+
+       appid = get_app_id_by_classid(classid, true);
+       return !appid ? UNKNOWN_APP : appid;
+}
+
+static void init_nfacct(u_int32_t classid, pid_t pid,
+       nfacct_rule_direction ctype, struct counter_arg *carg,
+       struct nfacct_rule *counter)
+{
+       counter->iotype = ctype;
+       counter->classid = classid;
+       counter->carg = carg;
+       counter->pid = pid;
+       counter->intend = NFACCT_COUNTER;
+       counter->quota = 0;
+       if (ctype == NFACCT_COUNTER_IN)
+               counter->iptables_rule = add_iptables_in;
+       else if (ctype == NFACCT_COUNTER_OUT)
+               counter->iptables_rule = add_iptables_out;
+}
+
+static resourced_ret_c del_counter(struct nfacct_rule *counter)
+{
+       return produce_net_rule(counter, 0, 0,
+               NFACCT_ACTION_DELETE, get_jump_by_intend(counter),
+               counter->iotype);
+}
+
+static int fill_restriction(struct rtattr *attr_list[__NFACCT_MAX],
+               void *user_data)
+{
+       struct counter_arg *carg = (struct counter_arg *)user_data;
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       char *cnt_name = (char *)RTA_DATA(
+                               attr_list[NFACCT_NAME]);
+       char *app_id = 0;
+       int ret = 0;
+       resourced_restriction_info rst_info = {0};
+
+       init_nfacct(0, 0, 0, carg, &counter);
+       strcpy(counter.name, cnt_name);
+       recreate_counter_by_name(cnt_name, &counter);
+
+       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!");
+
+       if (counter.intend == NFACCT_BLOCK) {
+               if (counter.iotype == NFACCT_COUNTER_IN) {
+                       struct nfacct_rule out_counter = counter;
+
+                       /* remove old ones, which were with notification */
+                       counter.iotype = NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT;
+                       ret = del_counter(&counter);
+                       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                               "Can't delete restriction%s", counter.name);
+
+                       out_counter.iotype = NFACCT_COUNTER_OUT;
+                       generate_counter_name(&out_counter);
+                       ret = add_iptables_out(&out_counter);
+                       /* TODO need to think how to release it and what about
+                        * not yet fired rule */
+                       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                               "Can't create auxilary counter %s", out_counter.name);
+               }
+
+               if (rst_info.quota_id != NONE_QUOTA_ID)
+                       send_restriction_notification(app_id);
+               update_restriction_db(app_id, counter.iftype, 0, 0,
+                                     RESOURCED_RESTRICTION_ACTIVATED,
+               rst_info.quota_id, rst_info.roaming);
+
+       } else if (counter.intend == NFACCT_WARN) {
+               if (rst_info.quota_id != NONE_QUOTA_ID)
+                       send_restriction_warn_notification(app_id);
+               /* remove both warnings */
+               counter.iotype = NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT;
+               ret = del_counter(&counter);
+               ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                       "Can't delete warning %s", counter.name);
+       } else
+               _E("Unkown restriction notification type");
+
+       return 0;
+}
+
+static Eina_Bool noti_func_cb(void *user_data, Ecore_Fd_Handler *fd_handler)
+{
+       struct counter_arg *carg = (struct counter_arg *)user_data;
+       struct genl ans;
+       struct netlink_serialization_params ser_param = {0};
+       netlink_serialization_command *netlink_command = NULL;
+       int ret;
+
+       _D("nfacct notification");
+       ret = read_netlink(carg->noti_fd, &ans, sizeof(struct genl));
+       if (ret == 0)
+               goto out;
+       carg->ans_len = ret;
+       ser_param.carg = carg;
+       ser_param.ans = &ans;
+       ser_param.eval_attr = fill_restriction;
+       netlink_command = netlink_create_command(&ser_param);
+
+       if (!netlink_command)
+               goto out;
+
+       netlink_command->deserialize_answer(&(netlink_command->params));
+
+out:
+       return ECORE_CALLBACK_RENEW;
+}
+
+static void init_notifier(struct counter_arg *carg)
+{
+       int ret = 0;
+       int option = NFNLGRP_ACCT_QUOTA;
+       struct sockaddr_nl addr;
+       socklen_t addr_len = sizeof(struct sockaddr_nl);
+
+       carg->noti_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
+       ret_msg_if(carg->noti_fd < 0, "Can't create socket");
+
+       /* bind */
+       memset(&addr, 0, sizeof(struct sockaddr_nl));
+       addr.nl_family = AF_NETLINK;
+       addr.nl_groups = 0;
+       addr.nl_pid = 0;
+
+       ret = bind(carg->noti_fd, (struct sockaddr *) &addr, addr_len);
+       ret_msg_if(ret < 0, "Can't bind notification socket");
+
+       ret = getsockname(carg->noti_fd, (struct sockaddr *)&addr, &addr_len);
+       ret_msg_if(ret < 0, "Can't get sockname!");
+
+       ret_msg_if(addr_len != sizeof(struct sockaddr_nl) ||
+               addr.nl_family != AF_NETLINK,
+               "getsockname bad argumetn");
+
+       /* see sock opt */
+
+       ret = setsockopt(carg->noti_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+               &option, sizeof(int));
+       ret_msg_if(carg->noti_fd < 0, "Can't set sock opt");
+
+       /* register handler */
+       carg->noti_fd_handler = ecore_main_fd_handler_add(
+               carg->noti_fd, ECORE_FD_READ, noti_func_cb,
+               carg, NULL, NULL);
+       ret_msg_if(carg->noti_fd_handler == NULL,
+                        "Failed to add noti callbacks\n");
+}
+
+static void fini_notifier(struct counter_arg *carg)
+{
+       shutdown(carg->noti_fd, SHUT_RDWR);
+       ecore_main_fd_handler_del(carg->noti_fd_handler);
+       close(carg->noti_fd);
+}
+
+/* end notification section */
+#else
+static int app_terminate_cb(void *data)
+{
+       return 0;
+}
+
+iface_callback *create_counter_callback(void)
+{
+       return NULL;
+}
+
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+
+static int resourced_datausage_init(void *data)
+{
+       struct modules_arg *marg = (struct modules_arg *)data;
+       struct shared_modules_data *m_data = get_shared_modules_data();
+       int ret_code;
+
+       load_daemon_opts(marg->opts);
+       _D("Initialize network counter function\n");
+       ret_value_msg_if(marg == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
+                        "Invalid modules argument\n");
+       ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
+                        "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_TERMINATE, app_terminate_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();
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+       reload_all_nf_counters(m_data->carg);
+
+       /* let's make a notification socket */
+       init_notifier(m_data->carg);
+#endif
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_datausage_finalize(void *data)
+{
+       struct shared_modules_data *m_data = get_shared_modules_data();
+
+       _D("Finalize network counter function\n");
+       resourced_remove_vconf_datausage_cb();
+       ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL,
+                        "Invalid shared modules data\n");
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+       remove_whole_nf_counters(m_data->carg);
+       fini_notifier(m_data->carg);
+#endif
+       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();
+
+       return RESOURCED_ERROR_NONE;
+}
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+
+static int compare_nfcntr(gconstpointer a, gconstpointer b,
+                     gpointer UNUSED user_data)
+{
+       struct nfacct_key *key_a = (struct nfacct_key *)a;
+       struct nfacct_key *key_b = (struct nfacct_key *)b;
+       int ret = key_a->classid - key_b->classid;
+
+       if (ret)
+               return ret;
+       ret = key_a->iftype - key_b->iftype;
+       if (ret)
+               return ret;
+       ret = key_a->iotype - key_b->iotype;
+       if (ret)
+               return ret;
+       return strcmp(key_a->ifname, key_b->ifname);
+}
+
+GTree *create_nfacct_tree(void)
+{
+       return g_tree_new_full(compare_nfcntr, NULL, NULL, free);
+}
+
+static struct nfacct_value *lookup_counter(struct nfacct_rule *counter)
+{
+       struct nfacct_key key = {
+               .classid = counter->classid,
+               .iftype = counter->iftype,
+               .iotype = counter->iotype
+       };
+       STRING_SAVE_COPY(key.ifname, counter->ifname);
+
+       return (struct nfacct_value *)g_tree_lookup(counter->carg->nf_cntrs,
+               &key);
+}
+
+/* Called only in case of successful kernle operation */
+void keep_counter(struct nfacct_rule *counter)
+{
+       struct nfacct_key *key = NULL;
+       struct nfacct_value *value = NULL;
+
+       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));
+
+       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;
+       STRING_SAVE_COPY(key->ifname, counter->ifname);
+
+       value->pid =  counter->pid;
+       value->state = NFACCT_STATE_ACTIVE;
+
+       g_tree_insert(counter->carg->nf_cntrs, key, value);
+}
+
+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;
+       struct nfacct_value *counter = NULL;
+
+       if (iftype <= RESOURCED_IFACE_UNKNOWN ||
+               iftype >= RESOURCED_IFACE_LAST_ELEM) {
+               _D("Unsupported network interface type %d",
+                       iftype);
+               return RESOURCED_ERROR_NONE;
+       }
+
+       ctx->counter->iftype = iftype;
+       generate_counter_name(ctx->counter);
+       counter = lookup_counter(ctx->counter);
+       if (counter != NULL) {
+               _D("Counter already exists!");
+               return RESOURCED_ERROR_NONE;
+       }
+       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);
+}
+
+static resourced_ret_c create_iptables_rule(const char *app_id, const pid_t pid)
+{
+       struct shared_modules_data *m_data = get_shared_modules_data();
+       struct counter_arg *carg = m_data->carg;
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       struct make_rule_context ctx;
+       uint32_t classid = get_classid_by_app_id(app_id, false);
+
+       ctx.carg = carg;
+       ctx.counter = &counter;
+       init_nfacct(classid, pid, NFACCT_COUNTER_IN, carg, &counter);
+
+       for_each_ifindex((ifindex_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,
+               populate_incomplete_counter, &ctx);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+/* iface reset section */
+struct iftype_context {
+       resourced_iface_type iftype;
+       struct counter_arg *carg;
+};
+
+static bool is_incomplete_counter(struct nfacct_key *nfacct_key, struct nfacct_value *nfacct_value)
+{
+       return nfacct_key->iftype == RESOURCED_IFACE_UNKNOWN &&
+               nfacct_value->state == NFACCT_STATE_ACTIVE;
+                       /* special incomplete status unnecessary */
+}
+
+static gboolean activate_each_counter_by_iftype(gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       struct nfacct_key *nfacct_key = (struct nfacct_key *)key;
+       struct nfacct_value *nfacct_value = (struct nfacct_value *)value;
+       struct iftype_context *ctx = (struct iftype_context *)data;
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       struct nfacct_value *found_counter;
+       int ret = RESOURCED_ERROR_NONE;
+
+       /* ugly check, due in case of RMNET -> WLAN switch,
+        *              WLAN activated before then RMNET is deactivated */
+
+       /*
+        * skip activating in case of
+        * 1. new interface is the same as was before
+        * 2. and counter is still active and new interface is Wifi
+        *      such problem was with WiFi only
+        * 3. and state is not deactivated, it's mean we wil skip in case of active
+        *   incomplete counter
+        * */
+       if (!(ctx->iftype != nfacct_key->iftype &&
+           nfacct_value->state == NFACCT_STATE_ACTIVE &&
+           ctx->iftype == RESOURCED_IFACE_WIFI) &&
+           nfacct_value->state != NFACCT_STATE_DEACTIVATED &&
+           !is_incomplete_counter(nfacct_key, nfacct_value))
+               /* it means ctx->iftype was activated, but we still have
+                *      active counter for another interface, assume
+                *      WLAN is preffered, so lets deactivate it */
+               return FALSE; /* continue iteration */
+
+
+       counter.classid = nfacct_key->classid;
+       counter.iotype = nfacct_key->iotype;
+       counter.iftype = ctx->iftype;
+       counter.carg = ctx->carg;
+
+       generate_counter_name(&counter);
+
+       found_counter = lookup_counter(&counter);
+       ret_value_msg_if(found_counter != NULL &&
+               found_counter->state == NFACCT_STATE_ACTIVE, FALSE,
+               "Counter already exists and active!");
+
+       if (counter.iotype == NFACCT_COUNTER_IN)
+               ret = add_iptables_in(&counter);
+       else if (counter.iotype == NFACCT_COUNTER_OUT)
+               ret = add_iptables_out(&counter);
+       else {
+               _E("Unknown counter direction: %s", counter.name);
+               return FALSE;
+       }
+
+       if (ret != RESOURCED_ERROR_NONE)
+               return FALSE;
+
+       if (found_counter != NULL && found_counter->state ==
+               NFACCT_STATE_DEACTIVATED)
+               found_counter->state = NFACCT_STATE_ACTIVE;
+       else
+               keep_counter(&counter);
+
+       return FALSE;
+}
+
+static void handle_on_iface_up(const int ifindex)
+{
+       /* NEW IFACE LET's add COUNTER if it DOESN"T exists */
+       resourced_iface_type iftype;
+       struct shared_modules_data *m_data;
+       struct iftype_context ctx;
+       m_data = get_shared_modules_data();
+       ret_msg_if(m_data == NULL,
+               "Can't get module data!");
+       iftype = get_iftype(ifindex);
+
+       ret_msg_if(iftype == RESOURCED_IFACE_UNKNOWN,
+               "Can't get iftype for remove counter");
+
+       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);
+}
+
+struct del_counter_context
+{
+       struct nfacct_value *nfacct_value;
+       struct nfacct_key *nfacct_key;
+       struct counter_arg *carg;
+};
+
+static Eina_Bool del_counter_delayed(void *data)
+{
+       int ret;
+       struct nfacct_rule counter = { .name = {0}, .ifname = {0}, 0, };
+       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;
+
+       counter.classid = nfacct_key->classid;
+       counter.iotype = nfacct_key->iotype;
+       counter.iftype = nfacct_key->iftype;
+       counter.carg = del_ctx->carg;
+       STRING_SAVE_COPY(counter.ifname, nfacct_key->ifname);
+
+       generate_counter_name(&counter);
+
+       ret = del_counter(&counter);
+
+       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ECORE_CALLBACK_CANCEL,
+               "Can't delete counter %s",
+               counter.name);
+
+       nfacct_value->state = NFACCT_STATE_DEACTIVATED;
+
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static gboolean deactivate_each_counter_by_iftype(gpointer key,
+       gpointer value,
+       gpointer data)
+{
+       struct nfacct_key *nfacct_key = (struct nfacct_key *)key;
+       struct nfacct_value *nfacct_value = (struct nfacct_value *)value;
+       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)
+               return FALSE; /* continue iteration */
+
+       del_ctx = (struct del_counter_context *)malloc(
+               sizeof(struct del_counter_context));
+       ret_value_msg_if(del_ctx == NULL, FALSE,
+               "Can't allocate del_counter_context");
+       del_ctx->nfacct_key = nfacct_key;
+       del_ctx->nfacct_value = nfacct_value;
+       del_ctx->carg = ctx->carg;
+       ecore_timer_add(0, del_counter_delayed, del_ctx);
+
+       return FALSE;
+}
+
+static void handle_on_iface_down(const int ifindex)
+{
+       /* iface is gone, lets remove counter */
+       resourced_iface_type iftype;
+       struct shared_modules_data *m_data;
+       struct iftype_context ctx;
+       m_data = get_shared_modules_data();
+       ret_msg_if(m_data == NULL,
+               "Can't get module data!");
+       iftype = get_iftype(ifindex);
+
+       ret_msg_if(iftype == RESOURCED_IFACE_UNKNOWN,
+               "Can't get iftype for remove counter");
+
+       ctx.iftype = iftype;
+       ctx.carg = m_data->carg;
+       g_tree_foreach(ctx.carg->nf_cntrs, deactivate_each_counter_by_iftype, &ctx);
+}
+
+iface_callback *create_counter_callback(void)
+{
+       iface_callback *ret_arg = (iface_callback *)
+               malloc(sizeof(iface_callback));
+
+       if (!ret_arg) {
+               _E("Malloc of iface_callback failed\n");
+               return NULL;
+       }
+       ret_arg->handle_iface_up = handle_on_iface_up;
+       ret_arg->handle_iface_down = handle_on_iface_down;
+
+       return ret_arg;
+}
+
+/* end iface reset section */
+
+#endif /*DATAUSAGE_TYPE*/
+
+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_if(ret != RESOURCED_ERROR_NONE, ret);
+       ret = update_classids();
+       ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
+#ifdef CONFIG_DATAUSAGE_NFACCT
+       /* Create iptable rule */
+       ret = create_iptables_rule(app_id, pid);
+       ret_value_if(ret != RESOURCED_ERROR_NONE, ret);
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+       return RESOURCED_ERROR_NONE;
+}
+
+static const struct module_ops datausage_modules_ops = {
+       .priority = MODULE_PRIORITY_NORMAL,
+       .name = "datausage",
+       .init = resourced_datausage_init,
+       .exit = resourced_datausage_finalize,
+};
+
+MODULE_REGISTER(&datausage_modules_ops)
diff --git a/src/network/datausage-quota-processing.c b/src/network/datausage-quota-processing.c
new file mode 100644 (file)
index 0000000..11822b4
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * 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 datausage-quota-processing.c
+ *
+ * @desc Quota processing implementation.
+ *     This implementation updates used quota table and determine
+ *     moment of time for blocking.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sqlite3.h>
+#include <inttypes.h>
+
+#include "database.h"
+#include "data_usage.h"
+#include "macro.h"
+#include "protocol-info.h"
+#include "resourced.h"
+#include "notification.h"
+#include "storage.h"
+#include "trace.h"
+#include "roaming.h"
+#include "datausage-restriction.h"
+#include "datausage-vconf-common.h"
+
+static GTree *quotas;
+static sqlite3_stmt *select_stmt;
+static sqlite3_stmt *insert_stmt;
+static sqlite3_stmt *clear_effective_stmt;
+
+static const char select_query[] = "SELECT qt.binpath, qt.sent_quota, qt.rcv_quota, "\
+       "qt.snd_warning_threshold, qt.rcv_warning_threshold, "\
+       "sent_used_quota, rcv_used_quota, qt.start_time AS quota_start_time, "\
+       "qt.time_period AS quota_period, efq.start_time AS effective_start, "\
+       "efq.finish_time AS effective_finish, qt.iftype AS iftype, " \
+       "qt.roaming, "\
+       "efq.state, "\
+       "qt.ROWID "\
+       "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) "\
+       "GROUP BY qt.binpath, qt.iftype, qt.sent_quota, qt.rcv_quota, " \
+       "qt.roaming";
+
+static const char insert_query[] = "REPLACE INTO effective_quotas " \
+       "(binpath, sent_used_quota, rcv_used_quota, " \
+       "start_time, finish_time, iftype, roaming, state) " \
+       " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+
+static const char clear_effective_quota_query[] = "DELETE FROM effective_quotas " \
+       " WHERE binpath = ? AND iftype = ? AND roaming = ?";
+
+enum resourced_quota_state {
+       RESOURCED_QUOTA_UNKNOWN,        /**< undefined/initial state */
+       RESOURCED_QUOTA_APPLIED,        /**< enabled/applied state */
+       RESOURCED_QUOTA_REVERTED,       /**< disabled/reverted state */
+};
+
+struct quota {
+       int quota_id;
+       int64_t send_quota;
+       int64_t rcv_quota;
+       int64_t sent_used_quota;
+       int64_t rcv_used_quota;
+       int snd_warning_threshold;
+       int rcv_warning_threshold;
+       int start_time;
+       int time_period;
+       int real_start;
+       int real_finish;
+       enum resourced_quota_state state;
+};
+
+struct quota_key {
+       const char *app_id;
+       resourced_iface_type iftype;
+       resourced_roaming_type roaming;
+};
+
+typedef enum {
+       DROP_UNDEF = 0,
+       DROP_NEED = 1,
+       DROP_NO_NEED = 2
+} drop_decision;
+
+static void obtain_and_keep_quotas(sqlite3_stmt *query)
+{
+       int rc = 0;
+       struct quota *value = 0;
+       struct quota_key *key = 0;
+
+       if (!query) {
+               _D("Can not update quotas: empty query");
+               return;
+       }
+
+       do {
+               rc = sqlite3_step(query);
+
+               if (rc == SQLITE_ERROR) {
+                       _E("Error updating quotas %s", sqlite3_errmsg(resourced_get_database()));
+                       return;
+               } else if (rc == SQLITE_ROW) {
+                       value = g_new0(struct quota, 1);
+                       if (!value) {
+                               _E("Can't allocate value for quota");
+                               return;
+                       }
+
+                       key = g_new0(struct quota_key, 1);
+                       if (!key) {
+                               _E("Can't allocate key for quota");
+                               goto free_value;
+                       }
+
+                       key->app_id = strdup((char *)sqlite3_column_text(
+                               query, 0));
+                       key->iftype = sqlite3_column_int(
+                               query, 11);
+                       key->roaming = sqlite3_column_int(
+                               query, 12);
+
+                       value->send_quota = sqlite3_column_int64(
+                               query, 1);
+                       value->rcv_quota = sqlite3_column_int64(
+                               query, 2);
+                       value->snd_warning_threshold = sqlite3_column_int64(
+                               query, 3);
+                       value->rcv_warning_threshold = sqlite3_column_int64(
+                               query, 4);
+                       value->sent_used_quota = sqlite3_column_int64(
+                               query, 5);
+                       value->rcv_used_quota = sqlite3_column_int64(
+                               query, 6);
+                       value->start_time = sqlite3_column_int64(
+                               query, 7);
+                       value->time_period = sqlite3_column_int64(
+                               query, 8);
+                       value->real_start = sqlite3_column_int64(
+                               query, 9);
+                       value->real_finish = sqlite3_column_int64(
+                               query, 10);
+                       value->state = sqlite3_column_int64(
+                               query, 13);
+                       value->quota_id = sqlite3_column_int(
+                               query, 14);
+
+                       g_tree_insert(quotas, key, value);
+               }
+       } while (rc == SQLITE_ROW);
+
+       return;
+free_value:
+       if (value)
+               g_free(value);
+}
+
+static gint compare_quota_key(gconstpointer a, gconstpointer b,
+       gpointer UNUSED user_data)
+{
+       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;
+}
+
+#define quota_key_destructor g_free
+#define quota_destructor g_free
+
+static void _clear_effective_quota(const char *app_id,
+       const resourced_iface_type iftype,
+       const resourced_roaming_type roaming)
+{
+       if (sqlite3_bind_text(clear_effective_stmt, 1, app_id, -1,
+                         SQLITE_TRANSIENT) != SQLITE_OK) {
+               _SE("Can not bind app_id:%s for preparing statement:%s",
+                       app_id, sqlite3_errmsg(resourced_get_database()));
+               return;
+       }
+
+       if (sqlite3_bind_int(clear_effective_stmt, 2, iftype)
+               != SQLITE_OK) {
+               _E("Can not bind iftype:%d for preparing statement:%s",
+                       iftype, sqlite3_errmsg(resourced_get_database()));
+               return;
+       }
+
+       if (sqlite3_bind_int(clear_effective_stmt, 3, roaming)
+               != SQLITE_OK) {
+               _E("Can not bind roaming:%d for preparing statement:%s",
+                       roaming, 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()));
+       sqlite3_reset(clear_effective_stmt);
+}
+
+static inline int _is_period_devisible(const int time_period,
+                                    data_usage_quota_period_t quota_period)
+{
+       return time_period > quota_period &&
+               time_period % RESOURCED_PERIOD_MONTH == 0;
+}
+
+/**
+ * @desc Define period base on stored in data base time interval
+ * @return time period
+ */
+static data_usage_quota_period_t _define_period(const int time_period, int *quantity)
+{
+       if (quantity == 0)
+               return RESOURCED_PERIOD_UNDEF;
+
+       if (_is_period_devisible(time_period, RESOURCED_PERIOD_MONTH)) {
+               *quantity = time_period / RESOURCED_PERIOD_MONTH;
+               return RESOURCED_PERIOD_MONTH;
+       }
+
+       if (_is_period_devisible(time_period, RESOURCED_PERIOD_MONTH)) {
+               *quantity = time_period / RESOURCED_PERIOD_MONTH;
+               return RESOURCED_PERIOD_MONTH;
+       }
+
+       if (_is_period_devisible(time_period, RESOURCED_PERIOD_WEEK)) {
+               *quantity = time_period / RESOURCED_PERIOD_WEEK;
+               return RESOURCED_PERIOD_WEEK;
+       }
+
+       if (_is_period_devisible(time_period, RESOURCED_PERIOD_DAY)) {
+               *quantity = time_period / RESOURCED_PERIOD_DAY;
+               return RESOURCED_PERIOD_DAY;
+       }
+
+       if (_is_period_devisible(time_period, RESOURCED_PERIOD_HOUR)) {
+               *quantity = time_period / RESOURCED_PERIOD_HOUR;
+               return RESOURCED_PERIOD_HOUR;
+       }
+
+       *quantity = time_period;
+       return RESOURCED_PERIOD_UNDEF;
+}
+
+
+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);
+
+       switch (_define_period(time_period, &quantity)) {
+       case RESOURCED_PERIOD_UNDEF:
+               return start_time + time_period;
+       case RESOURCED_PERIOD_HOUR:
+               new_start->tm_hour += quantity;
+       break;
+       case RESOURCED_PERIOD_DAY:
+               new_start->tm_mday += quantity;
+       break;
+       case RESOURCED_PERIOD_WEEK:
+               new_start->tm_mday += quantity * 7;
+       break;
+       case RESOURCED_PERIOD_MONTH:
+               new_start->tm_mon += quantity;
+       break;
+       }
+
+       /* normilize */
+       return mktime(new_start);
+}
+
+struct data_usage_context {
+       int64_t sent_used_quota;
+       int64_t rcv_used_quota;
+       resourced_roaming_type roaming;
+};
+
+static resourced_cb_ret data_usage_details_cb(const data_usage_info *info,
+                                              void *user_data)
+{
+       struct data_usage_context *context =
+               (struct data_usage_context *)user_data;
+
+       if (!context ||
+           (context->roaming != RESOURCED_ROAMING_UNKNOWN &&
+            context->roaming != info->roaming))
+               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 */
+}
+
+static void _record_quota(const struct quota_key *key,
+                         const struct quota *app_quota)
+{
+       if (!key || !app_quota) {
+               _E("Please, provide valid argument.");
+               return;
+       }
+
+       if (!app_quota->sent_used_quota &&
+           !app_quota->rcv_used_quota) {
+               _D("Nothing to store for effective quota.");
+               return;
+       }
+
+       if (sqlite3_bind_text(insert_stmt, 1, key->app_id, -1,
+                         SQLITE_STATIC) != SQLITE_OK) {
+               _SE("Can not bind app_id:%s for preparing statement",
+                       key->app_id);
+               return;
+       }
+
+       if (sqlite3_bind_int64(insert_stmt, 2, app_quota->sent_used_quota)
+               != SQLITE_OK) {
+               _E("Can not bind sent_used_quota:%lld for preparing statement",
+                       app_quota->sent_used_quota);
+               return;
+       }
+
+       if (sqlite3_bind_int64(insert_stmt, 3, app_quota->rcv_used_quota)
+               != SQLITE_OK) {
+               _E("Can not bind rcv_used_quota:%lld for preparing statement",
+                       app_quota->rcv_used_quota);
+               return;
+       }
+
+       if (sqlite3_bind_int64(insert_stmt, 4, app_quota->real_start)
+               != SQLITE_OK) {
+               _E("Can not bind start_time:%d for preparing statement",
+                       app_quota->real_start);
+               return;
+       }
+
+       if (sqlite3_bind_int64(insert_stmt, 5, app_quota->real_finish)
+               != SQLITE_OK) {
+               _E("Can not bind finish_time:%d for preparing statement",
+                       app_quota->real_finish);
+               return;
+       }
+
+       if (sqlite3_bind_int(insert_stmt, 6, key->iftype)
+               != SQLITE_OK) {
+               _E("Can not bind iftype:%d for preparing statement",
+                       key->iftype);
+               return;
+       }
+
+       if (sqlite3_bind_int(insert_stmt, 7, key->roaming)
+               != SQLITE_OK) {
+               _E("Can not bind roaming:%d for preparing statement",
+                       key->roaming);
+               return;
+       }
+
+       if (sqlite3_bind_int(insert_stmt, 8, app_quota->state)
+               != SQLITE_OK) {
+               _E("Can not bind state:%d for preparing statement",
+                       app_quota->state);
+               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,
+       const resourced_iface_type iftype, const time_t start_time,
+       const int time_period,
+       const resourced_roaming_type roaming)
+{
+       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);
+
+       if (cur_time < start_time) {
+               _D("No need to update effective quota!");
+               return;
+       }
+
+       out_context.roaming = roaming;
+       rule.from = start_time;
+       rule.to = cur_time;
+       rule.iftype = iftype;
+
+       if (data_usage_details_foreach(app_id, &rule, data_usage_details_cb,
+                                      &out_context) != RESOURCED_ERROR_NONE) {
+               _E("Cant obtain sent_used_quota/rcv_used_quota");
+               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);
+}
+
+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)
+{
+       struct quota_key key;
+       struct quota *tree_value;
+
+       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);
+
+       if (tree_value && tree_value->state == RESOURCED_QUOTA_APPLIED) {
+               _SD("Removing quota and restriction for %s,%d", app_id, iftype);
+               /* 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 (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);
+}
+
+static resourced_ret_c _init_quotas(void)
+{
+       execute_once {
+               quotas = g_tree_new_full(compare_quota_key, NULL,
+                       quota_key_destructor, quota_destructor);
+       }
+
+       if (!resourced_get_database())
+               return RESOURCED_ERROR_DB_FAILED;
+
+       if (select_stmt && insert_stmt)
+               return RESOURCED_ERROR_NONE;
+
+       if (sqlite3_prepare_v2(resourced_get_database(),
+                              select_query, -1, &select_stmt,
+                              NULL) != SQLITE_OK) {
+               _E("Error preparing query: %s, \
+                  %s\n", select_query, sqlite3_errmsg(resourced_get_database()));
+               goto handle_error;
+       }
+
+       if (sqlite3_prepare_v2(resourced_get_database(),
+                              insert_query, -1, &insert_stmt,
+                              NULL) != SQLITE_OK) {
+               _E("Error preparing query: %s, \
+                  %s\n", insert_query, sqlite3_errmsg(resourced_get_database()));
+               goto handle_error;
+       }
+
+       if (sqlite3_prepare_v2(resourced_get_database(),
+                              clear_effective_quota_query,
+                              -1, &clear_effective_stmt,
+                              NULL) != SQLITE_OK) {
+               _E("Error preparing query: %s, \
+                  %s\n", clear_effective_quota_query,
+                       sqlite3_errmsg(resourced_get_database()));
+               goto handle_error;
+       }
+
+       return RESOURCED_ERROR_NONE;
+handle_error:
+       /* Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op */
+       sqlite3_finalize(select_stmt);
+       sqlite3_finalize(insert_stmt);
+       sqlite3_finalize(clear_effective_stmt);
+       return RESOURCED_ERROR_DB_FAILED;
+}
+
+
+/**
+ * Update quotas tree, where app_id will the key
+ */
+static resourced_ret_c _update_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;
+}
+
+static const int64_t quota_gap_value[RESOURCED_IFACE_ALL] = {
+       5000,   /* ~4.5MB UNKNOWN */
+       5000,   /* ~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_DATACALL_3G, 7Mb/s on QC device */
+       475000, /* RESOURCED_PROTOCOL_DATACALL_HSDPA */
+       5000000,/* RESOURCED_PROTOCOL_DATACALL_LTE */
+};
+
+/*
+ * @desc this function returns valud per second
+ */
+static int64_t _get_quota_gap(const resourced_iface_type iftype)
+{
+
+       const resourced_hw_net_protocol_type proto = get_hw_net_protocol_type(iftype);
+
+       if (proto != RESOURCED_PROTOCOL_NONE)
+               return quota_datacall_gap_value[proto];
+
+       if (iftype > RESOURCED_IFACE_UNKNOWN &&
+           iftype < RESOURCED_IFACE_ALL)
+               return quota_gap_value[iftype];
+
+       return quota_gap_value[RESOURCED_IFACE_UNKNOWN];
+}
+
+int _is_under_restriction(const int64_t send_delta,
+       const int64_t rcv_delta,
+       const resourced_iface_type iftype,
+       int update_period)
+{
+       /* multiply on 2, due  */
+       const int64_t quota_gap = _get_quota_gap(iftype) * update_period;
+
+       _D("send_delta %"PRId64" rcv_delta%"PRId64" quota_gap %"PRId64""
+                "update_period %d ",
+               send_delta, rcv_delta, quota_gap, update_period);
+       return send_delta <= quota_gap ||
+               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)
+{
+       ret_msg_if(!app_quota, "Please provide valid pointer");
+
+       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
+                                               not procced it*/
+       }
+       return limit - threshold;
+}
+
+static int cast_restriction_limit(int64_t delta)
+{
+       if (delta < 0)
+               return 0;
+       if (delta > INT_MAX)
+               return INT_MAX;
+       return delta;
+}
+
+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;
+       resourced_net_restrictions rst = { RESOURCED_STATE_UNKNOWN,
+                                          RESOURCED_IFACE_UNKNOWN };
+
+       /* do not check already applied quota*/
+       if (app_quota->state == RESOURCED_QUOTA_APPLIED)
+               return FALSE;
+
+       send_delta = app_quota->send_quota - app_quota->sent_used_quota;
+       rcv_delta = app_quota->rcv_quota - app_quota->rcv_used_quota;
+
+       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);
+
+       if (_is_under_restriction(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;
+
+               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);
+
+               _SD("Applying quota for %s, iftype %d", key_quota->app_id,
+                   key_quota->iftype);
+               rst.iftype = key_quota->iftype;
+
+               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.");
+               }
+       }
+
+       return FALSE; /* continue iteration */
+}
+
+static void check_and_apply_quota(volatile struct daemon_opts *opts)
+{
+       g_tree_foreach(quotas, check_and_apply_node, (void *)opts);
+}
+
+struct update_all_arg
+{
+       resourced_iface_type iftype;
+       struct application_stat *app_stat;
+};
+
+static gboolean update_pseudo_app_entry(gpointer key,
+       gpointer value, gpointer user_data)
+{
+       struct update_all_arg *arg = (struct
+               update_all_arg *)user_data;
+       const struct quota_key *qkey = (const struct
+               quota_key *)key;
+
+       /* 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) &&
+            (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;
+               /* 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",
+                  total_quota->sent_used_quota, total_quota->rcv_used_quota,
+                       arg->iftype, arg->app_stat->ifindex);
+
+       }
+
+       return FALSE;
+}
+
+static void update_all_app_quotas(struct update_all_arg *update_all_arg)
+{
+       /* Now RESOURCED_ALL_APP can contain many iftypes */
+       g_tree_foreach(quotas, update_pseudo_app_entry, update_all_arg);
+}
+
+static void update_traffic_quota(const struct quota_key *quota_key,
+                                uint32_t *snd_count,
+                                uint32_t *rcv_count)
+{
+       struct quota *found_quota = g_tree_lookup(quotas, quota_key);
+
+       if (!found_quota)
+               return;
+       if (time(0) < found_quota->start_time) {
+               _D("No need to update effective quota!");
+               return;
+       }
+       found_quota->sent_used_quota += *snd_count;
+       found_quota->rcv_used_quota += *rcv_count;
+       _D("update total_quota tx:%"PRId64";rx:%"PRId64"\n",
+          found_quota->sent_used_quota, found_quota->rcv_used_quota);
+
+       _D("delta_rcv %d app_id %s\n", *rcv_count, quota_key->app_id);
+       *snd_count = 0;
+       *rcv_count = 0;
+       return;
+}
+
+static gboolean update_each_quota(gpointer key, gpointer value,
+       gpointer UNUSED userdata)
+{
+       const struct classid_iftype_key *app_key =
+               (const struct classid_iftype_key *)key;
+       struct application_stat *app_stat =
+               (struct application_stat *)value;
+       struct update_all_arg arg = {
+               .iftype = app_key->iftype,
+               .app_stat = app_stat
+       };
+       struct quota_key qkey;
+
+       /* We should handle cases of RESOURCED_ALL_APP or TETHERING_APP_NAME
+          in separate way due it's not comming with statistics from kernel */
+       update_all_app_quotas(&arg);
+
+       if (!app_stat->application_id)
+               return FALSE;
+
+       qkey.app_id = app_stat->application_id;
+       qkey.iftype = app_key->iftype;
+       qkey.roaming = app_stat->is_roaming;
+       update_traffic_quota(&qkey, &app_stat->delta_snd,
+                            &app_stat->delta_rcv);
+       return FALSE;
+}
+
+static void actualize_quota_table(struct application_stat_tree *apps)
+{
+       g_tree_foreach((GTree *)apps->tree, update_each_quota, NULL);
+}
+
+/**
+ * @desc Assume app_quota is not null
+ */
+static void calculate_finish_time(struct quota *app_quota)
+{
+       if (!app_quota || app_quota->real_finish)
+               return;
+
+       if (!app_quota->real_start)
+               app_quota->real_start = time(0);
+
+       app_quota->real_finish = _get_finish_time(app_quota->real_start,
+               app_quota->time_period);
+}
+
+/**
+ * @desc Reset quota. This function sets new real_start based on fihish time.
+ * Assume app_quota is set and  time(0) < app_quota->real_finish
+ */
+static void reset_quota(struct quota *app_quota)
+{
+       _D("reset_quota called");
+       app_quota->real_start = app_quota->real_finish;
+       app_quota->real_finish = 0;
+       app_quota->sent_used_quota = app_quota->rcv_used_quota = 0;
+       restriction_set_status(RESTRICTION_STATE_UNSET);
+}
+
+/**
+ * @desc Remove restriction if needed
+ */
+static void drop_restriction(const struct quota_key *qkey, struct quota *app_quota)
+{
+       if (!app_quota || !qkey) {
+               _E("Please provide valid arguments!");
+               return;
+       }
+
+       /* We can revert only applied quotas */
+       if (app_quota->state != RESOURCED_QUOTA_APPLIED)
+               return;
+
+       _SD("Removing restriction of quota for %s,%d", qkey->app_id,
+           qkey->iftype);
+       if (remove_restriction_local(qkey->app_id, qkey->iftype)
+           == RESOURCED_ERROR_NONE)
+               app_quota->state = RESOURCED_QUOTA_REVERTED;
+}
+
+/**
+ * @desc This function actualize current quotas states. It calculate new
+ *  finish time and remove restriction if exists.
+ */
+static gboolean flush_quota_node(gpointer key,
+       gpointer value, gpointer UNUSED user_data)
+{
+       struct quota *app_quota = value;
+       struct quota_key *key_quota = key;
+
+       if (!app_quota || !key_quota->app_id)
+               return FALSE; /* continue iteration even
+               current data is empty */
+
+       calculate_finish_time(app_quota);
+
+       _record_quota(key_quota, app_quota);
+       /* It's time to reset */
+       if (time(0) >= app_quota->real_finish) {
+               drop_restriction(key_quota, app_quota);
+               reset_quota(app_quota);
+       }
+       return FALSE;
+}
+
+/**
+ * Save to database effective quota
+ */
+void flush_quota_table(void)
+{
+       g_tree_foreach(quotas, flush_quota_node, NULL);
+}
+
+static void finalize_statement(sqlite3_stmt **stmt)
+{
+       if (*stmt) {
+               sqlite3_finalize(*stmt);
+               *stmt = NULL;
+       }
+}
+
+resourced_ret_c process_quota(struct application_stat_tree *apps,
+       volatile struct daemon_opts *opts)
+{
+       /* For first initialization */
+       static int quota_updated;
+
+       if (opts && opts->is_update_quota) {
+               const int error = _update_quotas();
+               if (error)
+                       return error;
+               quota_updated = 1;
+       }
+
+       actualize_quota_table(apps);
+
+       check_and_apply_quota(opts);
+
+       /* finilize state */
+       if (opts && opts->is_update_quota && quota_updated) {
+               opts->is_update_quota = 0;
+               quota_updated = 0;
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * Release  statement
+ */
+void finalize_quotas(void)
+{
+       finalize_statement(&insert_stmt);
+       finalize_statement(&select_stmt);
+       finalize_statement(&clear_effective_stmt);
+       g_tree_destroy(quotas);
+}
+
diff --git a/src/network/datausage-quota.c b/src/network/datausage-quota.c
new file mode 100644 (file)
index 0000000..60c09e7
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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 datausage-quota.c
+ *
+ * @desc Quota logic implementation
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <inttypes.h>
+#include <sqlite3.h>
+#include <string.h>
+#include <time.h>
+#include <vconf.h>
+
+#include "const.h"
+#include "const.h"
+#include "data_usage.h"
+#include "database.h"
+#include "datausage-quota.h"
+#include "edbus-handler.h"
+#include "macro.h"
+#include "trace.h"
+
+static resourced_ret_c send_quota_message(const char *interface,
+       const char *format_str, char *params[])
+{
+       DBusError err;
+       DBusMessage *msg;
+       resourced_ret_c ret_val;
+       int ret, i = 0;
+
+       do {
+               msg = dbus_method_sync(BUS_NAME, RESOURCED_PATH_NETWORK,
+                                      RESOURCED_INTERFACE_NETWORK,
+                                      interface,
+                                      format_str, 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 RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val,
+                                   DBUS_TYPE_INVALID);
+
+       if (ret == FALSE) {
+               _E("no message : [%s:%s]\n", err.name, err.message);
+               ret_val = RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_message_unref(msg);
+       dbus_error_free(&err);
+
+       return ret_val;
+}
+
+static resourced_ret_c send_create_quota_message(const char *app_id,
+       const data_usage_quota *quota)
+{
+       char *params[10];
+       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);
+       snprintf(rcv_quota, sizeof(rcv_quota), "%" PRId64 "", quota->rcv_quota);
+
+       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",
+               params);
+}
+
+static resourced_ret_c send_remove_quota_message(const char *app_id,
+       const resourced_iface_type iftype,
+       const resourced_roaming_type roaming_type)
+{
+       char *params[3];
+
+       serialize_params(params, ARRAY_SIZE(params), app_id, iftype,
+               roaming_type);
+       return send_quota_message(RESOURCED_NETWORK_REMOVE_QUOTA, "sdd",
+               params);
+}
+
+API resourced_ret_c remove_datausage_quota(
+       const struct datausage_quota_reset_rule *rule)
+{
+       if (!rule || !rule->app_id)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (rule->iftype <= RESOURCED_IFACE_UNKNOWN ||
+           rule->iftype >= RESOURCED_IFACE_LAST_ELEM)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (rule->roaming < RESOURCED_ROAMING_UNKNOWN ||
+           rule->roaming >= RESOURCED_ROAMING_LAST_ELEM)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       return send_remove_quota_message(rule->app_id, rule->iftype,
+                rule->roaming);
+}
+
+API resourced_ret_c remove_datausage_quota_by_iftype(
+       const char *app_id, const resourced_iface_type iftype)
+{
+       struct datausage_quota_reset_rule rule = {
+               .app_id = app_id,
+               .iftype = iftype,
+               .roaming = RESOURCED_ROAMING_UNKNOWN,
+       };
+
+       return remove_datausage_quota(&rule);
+}
+
+static int _is_valid_datausage_quota_params(const char *app_id,
+                                       const data_usage_quota *quota)
+{
+       if (!app_id) {
+               _SE("Empty appid! Please provide valid appid.");
+               return 0;
+       }
+
+       if (!quota) {
+               _E("Empty quota! Please provide valid quota.");
+               return 0;
+       }
+
+       if (quota->iftype >= RESOURCED_IFACE_LAST_ELEM) {
+               _E("Not valid value for iftype! See resourced_iface_type!");
+               return 0;
+       }
+
+       return 1;
+}
+
+static time_t _get_datausage_start_time(const time_t *quota_start_time)
+{
+       return quota_start_time ? *quota_start_time : time(0);
+}
+
+API resourced_ret_c set_datausage_quota(const char *app_id,
+                                       const data_usage_quota *quota)
+{
+       /* support old behaviour undefined iftype mean all iftype */
+       time_t start_time = 0;
+       data_usage_quota quota_to_send;
+
+       if (!_is_valid_datausage_quota_params(app_id, quota))
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       quota_to_send = *quota;
+       start_time = _get_datausage_start_time(quota->start_time);
+       quota_to_send.start_time = &start_time;
+
+       _SD("quota for app %s set", app_id);
+       _SD("===============================");
+       _SD("quota.start_time = %s", ctime(quota->start_time));
+       _SD("quota.time_period = %d", quota->time_period);
+       _SD("quota.snd_quota = %lld", quota->snd_quota);
+       _SD("quota.rcv_quota = %lld", quota->rcv_quota);
+       _SD("quota.quota_type = %d", quota->quota_type);
+       _SD("quota.iftype = %d", quota->iftype);
+       _SD("===============================");
+
+       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
new file mode 100644 (file)
index 0000000..ae9098a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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: datausage-vconf-callbacks.c
+ *
+ *  @desc Add datausage callback functions to vconf
+ *
+ */
+
+#include "const.h"
+#include "counter.h"
+#include "daemon-options.h"
+#include "datausage-vconf-callbacks.h"
+#include "datausage-quota-processing.h"
+#include "datausage-quota.h"
+#include "iface.h"
+#include "macro.h"
+#include "resourced.h"
+#include "settings.h"
+#include "trace.h"
+
+#include <stdlib.h>
+#include <vconf.h>
+
+static void wifi_change_cb(keynode_t *key, void *data)
+{
+       int val = vconf_keynode_get_bool(key);
+       _SD("key = %s, value = %d(int)\n",
+           vconf_keynode_get_name(key), val);
+       set_wifi_allowance(val ?
+                          RESOURCED_OPTION_ENABLE : RESOURCED_OPTION_DISABLE);
+}
+
+static void datacall_change_cb(keynode_t *key, void *data)
+{
+       int val = vconf_keynode_get_bool(key);
+
+       _SD("key = %s, value = %d(int)\n",
+           vconf_keynode_get_name(key), val);
+       set_datacall_allowance(val ? RESOURCED_OPTION_ENABLE :
+                              RESOURCED_OPTION_DISABLE);
+}
+
+static void datacall_logging_change_cb(keynode_t *key, void *data)
+{
+       struct daemon_opts *options = (struct daemon_opts *)data;
+       int val = vconf_keynode_get_bool(key);
+
+       if (!options) {
+               _E("Please provide valid argument!");
+               return;
+       }
+       _SD("key = %s, value = %d(int)\n",
+           vconf_keynode_get_name(key), val);
+       options->datacall_logging = val ? RESOURCED_OPTION_ENABLE :
+               RESOURCED_OPTION_DISABLE;
+}
+
+static void datausage_timer_change_cb(keynode_t *key, void *data)
+{
+       struct daemon_opts *options = (struct daemon_opts *)data;
+       int val = vconf_keynode_get_int(key);
+
+       if (!options) {
+               _E("Please provide valid argument!");
+               return;
+       }
+       _SD("key = %s, value = %d(int)\n",
+           vconf_keynode_get_name(key), val);
+
+       options->update_period = val;
+}
+
+void resourced_add_vconf_datausage_cb(struct counter_arg *carg)
+{
+       _D("Add vconf datausage callbacks\n");
+       ret_msg_if(!carg || !carg->opts,
+                        "Please provide valid argument!");
+       vconf_notify_key_changed(RESOURCED_WIFI_STATISTICS_PATH, wifi_change_cb,
+                                NULL);
+       vconf_notify_key_changed(RESOURCED_DATACALL_PATH, datacall_change_cb,
+                                NULL);
+       vconf_notify_key_changed(RESOURCED_DATAUSAGE_TIMER_PATH,
+                                datausage_timer_change_cb, (void *)carg->opts);
+       vconf_notify_key_changed(RESOURCED_DATACALL_LOGGING_PATH,
+                                datacall_logging_change_cb,
+                                (void *)carg->opts);
+}
+
+void resourced_remove_vconf_datausage_cb(void)
+{
+       _D("Remove vconf datausage callbacks\n");
+       vconf_ignore_key_changed(RESOURCED_WIFI_STATISTICS_PATH,
+                                wifi_change_cb);
+       vconf_ignore_key_changed(RESOURCED_DATACALL_PATH, datacall_change_cb);
+       vconf_ignore_key_changed(RESOURCED_DATAUSAGE_TIMER_PATH,
+                                datausage_timer_change_cb);
+       vconf_ignore_key_changed(RESOURCED_DATACALL_LOGGING_PATH,
+                                datacall_logging_change_cb);
+}
diff --git a/src/network/datausage-vconf-common.c b/src/network/datausage-vconf-common.c
new file mode 100644 (file)
index 0000000..3d914b1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#include <resourced.h>
+#include <vconf.h>
+
+#include "trace.h"
+#include "data_usage.h"
+#include "datausage-vconf-common.h"
+
+#ifndef VCONFKEY_SETAPPL_SET_DATA_USAGE_LIMIT_BOOL
+#define VCONFKEY_SETAPPL_SET_DATA_USAGE_LIMIT_BOOL "db/setting/set_data_usage_limit"
+#endif
+
+#ifndef VCONFKEY_SETAPPL_DATA_LIMIT_INT
+#define VCONFKEY_SETAPPL_DATA_LIMIT_INT "db/setting/data_limit"
+#endif
+
+#ifndef VCONFKEY_SETAPPL_DATA_RESTRICTION_INT
+#define VCONFKEY_SETAPPL_DATA_RESTRICTION_INT "db/setting/data_restriction"
+#endif
+
+resourced_ret_c restriction_check_limit_status(int *retval)
+{
+       if (vconf_get_bool(VCONFKEY_SETAPPL_SET_DATA_USAGE_LIMIT_BOOL, retval)) {
+               _E("vconf_get_bool FAIL\n");
+               return RESOURCED_ERROR_FAIL;
+       };
+
+       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;
+
+       if (vconf_get_int(VCONFKEY_SETAPPL_DATA_RESTRICTION_INT, &limit)) {
+               _E("vconf_get_int FAIL\n");
+               return;
+       }
+
+       if (limit == value) {
+               _E("No need to change a restriction status: %d", limit);
+               return;
+       }
+
+       vconf_set_int(VCONFKEY_SETAPPL_DATA_RESTRICTION_INT, value);
+       return;
+}
diff --git a/src/network/dummy-tethering.c b/src/network/dummy-tethering.c
new file mode 100644 (file)
index 0000000..9c18243
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 dummy-tethering.c
+ *
+ * @desc Collect here all tethering related function with empty
+ * body
+ */
+
+#include "app-stat.h"
+#include "macro.h"
+#include "transmission.h"
+
+#include "data_usage.h"
+
+#include <vconf.h>
+
+resourced_ret_c apply_tethering_restriction(
+       UNUSED const enum traffic_restriction_type type)
+{
+       return RESOURCED_ERROR_NONE;
+}
+
+void tethering_state_change_cb(keynode_t *key, void UNUSED *data)
+{
+}
+
diff --git a/src/network/dummy_roaming.c b/src/network/dummy_roaming.c
new file mode 100644 (file)
index 0000000..c67fee6
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  resourced
+ *
+ * Copyright (c) 2013 - 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 roaming.c
+ *
+ * @desc It's dummy implementation for none telephony case.
+ */
+
+#include "macro.h"
+#include "roaming.h"
+#include "trace.h"
+
+/* for avoiding dependency in this file */
+
+void regist_roaming_cb(roaming_cb UNUSED cb)
+{
+       _D("ROAMING ISN'T SUPPORTED, CHECK TELEPHONY MODULE");
+}
+
+resourced_roaming_type get_roaming(void)
+{
+       _D("ROAMING ISN'T SUPPORTED, CHECK TELEPHONY MODULE");
+       return RESOURCED_ROAMING_UNKNOWN;
+}
+
diff --git a/src/network/foreach.c b/src/network/foreach.c
new file mode 100644 (file)
index 0000000..0afb353
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * 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 foreach.c
+ * @desc Implementation of the datausage foreach function.
+ *
+ */
+
+
+#include <sqlite3.h>
+#include <string.h>
+
+#include "database.h"
+#include "data_usage.h"
+#include "datausage-foreach.h"
+#include "macro.h"
+#include "trace.h"
+
+#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"
+
+#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"
+
+#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 " \
+       "from statistics where time_stamp between ? and ? " \
+       "group by binpath, time_stamp 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, "                 \
+       "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"
+
+#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"
+
+#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=?"
+
+#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"
+
+#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 " \
+       "from statistics where time_stamp between ? and ? and binpath = ? " \
+       "and iftype = ? group by time_stamp order by time_stamp"
+
+#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"
+
+#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=?"
+
+#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 " \
+       "from statistics where time_stamp between ? and ? "             \
+       "group by iftype, time_stamp order by time_stamp, iftype"
+
+#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 " \
+       "from statistics where time_stamp between ? and ? "             \
+       "and iftype = ? group by time_stamp order by time_stamp"
+
+static sqlite3_stmt *data_usage_for_period;
+static sqlite3_stmt *data_usage_for_period_iface;
+static sqlite3_stmt *data_usage_chunks;
+static sqlite3_stmt *data_usage_chunks_iface;
+static sqlite3_stmt *data_usage_app_details;
+static sqlite3_stmt *data_usage_app_details_iface;
+static sqlite3_stmt *data_usage_chunks_app;
+static sqlite3_stmt *data_usage_chunks_app_iface;
+static sqlite3_stmt *data_usage_total;
+static sqlite3_stmt *data_usage_total_iface;
+static sqlite3_stmt *data_usage_chunks_total;
+static sqlite3_stmt *data_usage_chunks_total_iface;
+
+#define PREPARE(stm, query) do {                               \
+       rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
+       if (rc != SQLITE_OK) {                                  \
+               stm = NULL;                                     \
+               finalize_datausage_foreach();                           \
+               _E("Failed to prepare %s\n", query);            \
+               return rc;                                      \
+       }                                                       \
+} while (0)
+
+int init_datausage_foreach(sqlite3 *db)
+{
+       int rc;
+       static int initialized;
+
+       if (initialized)
+               return SQLITE_OK;
+
+       PREPARE(data_usage_for_period, DATA_USAGE_FOR_PERIOD);
+       PREPARE(data_usage_for_period_iface, DATA_USAGE_FOR_PERIOD_IFACE);
+       PREPARE(data_usage_chunks, DATA_USAGE_CHUNKS);
+       PREPARE(data_usage_chunks_iface, DATA_USAGE_CHUNKS_IFACE);
+       PREPARE(data_usage_app_details, DATA_USAGE_APP_DETAILS);
+       PREPARE(data_usage_app_details_iface, DATA_USAGE_APP_DETAILS_IFACE);
+       PREPARE(data_usage_chunks_app, DATA_USAGE_CHUNKS_APP);
+       PREPARE(data_usage_chunks_app_iface, DATA_USAGE_CHUNKS_APP_IFACE);
+       PREPARE(data_usage_total, DATA_USAGE_TOTAL);
+       PREPARE(data_usage_total_iface, DATA_USAGE_TOTAL_IFACE);
+       PREPARE(data_usage_chunks_total, DATA_USAGE_CHUNKS_TOTAL);
+       PREPARE(data_usage_chunks_total_iface, DATA_USAGE_CHUNKS_TOTAL_IFACE);
+
+       initialized = 1;
+       return SQLITE_OK;
+}
+
+#define FINALIZE(stm) do {             \
+       if (stm) {                      \
+               sqlite3_finalize(stm);  \
+               stm = NULL;             \
+       }                               \
+} while (0)
+
+void finalize_datausage_foreach(void)
+{
+       FINALIZE(data_usage_for_period);
+       FINALIZE(data_usage_for_period_iface);
+       FINALIZE(data_usage_chunks);
+       FINALIZE(data_usage_chunks_iface);
+       FINALIZE(data_usage_app_details);
+       FINALIZE(data_usage_app_details_iface);
+       FINALIZE(data_usage_chunks_app);
+       FINALIZE(data_usage_chunks_app_iface);
+       FINALIZE(data_usage_total);
+       FINALIZE(data_usage_total_iface);
+       FINALIZE(data_usage_chunks_total);
+       FINALIZE(data_usage_chunks_total_iface);
+}
+
+static int is_iftype_defined(const resourced_iface_type iftype)
+{
+       return iftype < RESOURCED_IFACE_LAST_ELEM &&
+              iftype > RESOURCED_IFACE_UNKNOWN &&
+              iftype != RESOURCED_IFACE_ALL;
+}
+
+API resourced_ret_c data_usage_foreach(const data_usage_selection_rule *rule,
+                                      data_usage_info_cb info_cb,
+                                      void *user_data)
+{
+       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 */
+       resourced_tm_interval interval;
+
+       libresourced_db_initialize_once();
+       if (init_datausage_foreach(resourced_get_database())!= SQLITE_OK) {
+               _D("Failed to initialize data usage statements: %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+
+
+       memset(&data, 0, sizeof(data));
+
+       if (!rule || !info_cb)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       /* pick a statement depending on parameters */
+       if (rule->granularity) {
+               stm = is_iftype_defined(rule->iftype) ?
+                       data_usage_chunks_iface : data_usage_chunks;
+
+               if (sqlite3_bind_int64(stm, pos++, rule->granularity) !=
+                   SQLITE_OK) {
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       goto out;
+               }
+               data.interval = &interval;
+       } else {
+               stm = is_iftype_defined(rule->iftype)
+                   ? data_usage_for_period_iface : data_usage_for_period;
+       }
+
+       if (sqlite3_bind_int64(stm, pos++, rule->from) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+       if (sqlite3_bind_int64(stm, pos++, rule->to) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (is_iftype_defined(rule->iftype)) {
+               data.iftype = rule->iftype;
+               if (sqlite3_bind_int
+                   (stm, pos++, rule->iftype) != SQLITE_OK) {
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       goto out;
+               }
+       }
+
+       do {
+               rc = sqlite3_step(stm);
+               switch (rc) {
+               case SQLITE_ROW:
+                       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);
+                       if (rule->granularity) {
+                               interval.from = sqlite3_column_int64(stm, 5);
+                               interval.to = interval.from + rule->granularity;
+                       }
+
+                       if (info_cb(&data, user_data) == RESOURCED_CANCEL)
+                               rc = SQLITE_DONE;/* emulate end of data */
+                       break;
+               case SQLITE_DONE:
+                       break;
+               case SQLITE_ERROR:
+               default:
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       break;
+               }
+       } while (rc == SQLITE_ROW);
+ out:
+       sqlite3_reset(stm);
+       return result;
+}
+
+/* the following array is strictly ordered
+ * to find required statement the following code will be used:
+ * (iface ? 1 : 0) | (total ? 2 : 0) | (chunks ? 4 : 0)
+ */
+static sqlite3_stmt **details_stms[] = {
+       &data_usage_app_details,
+       &data_usage_app_details_iface,
+       &data_usage_total,
+       &data_usage_total_iface,
+       &data_usage_chunks_app,
+       &data_usage_chunks_app_iface,
+       &data_usage_chunks_total,
+       &data_usage_chunks_total_iface
+};
+
+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)];
+}
+
+API resourced_ret_c data_usage_details_foreach(const char *app_id,
+                                    data_usage_selection_rule *rule,
+                                    data_usage_info_cb info_cb, void *user_data)
+{
+       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 */
+       resourced_tm_interval interval;
+
+       libresourced_db_initialize_once();
+       if (init_datausage_foreach(resourced_get_database())!= SQLITE_OK) {
+               _D("Failed to initialize data usage statements: %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+       memset(&data, 0, sizeof(data));
+
+       if (!rule || !info_cb)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       /* pick a statement depending on parameters.
+               See comment for details_stms */
+       stm = select_statement(app_id, rule);
+
+       if (rule->granularity) {
+               if (sqlite3_bind_int64(stm, pos++, rule->granularity) !=
+                   SQLITE_OK) {
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       goto out;
+               }
+               data.interval = &interval;
+       }
+
+       if (sqlite3_bind_int64(stm, pos++, rule->from) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+       if (sqlite3_bind_int64(stm, pos++, rule->to) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (app_id) {
+               if (sqlite3_bind_text(stm, pos++, app_id, -1, SQLITE_TRANSIENT)
+                   != SQLITE_OK) {
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       goto out;
+               }
+               data.app_id = app_id;
+       }
+
+       if (is_iftype_defined(rule->iftype)) {
+               if (sqlite3_bind_int
+                   (stm, pos++, rule->iftype) != SQLITE_OK) {
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       goto out;
+               }
+       }
+
+       do {
+               rc = sqlite3_step(stm);
+               switch (rc) {
+               case SQLITE_ROW:
+                       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.ifname = (char *)sqlite3_column_text(stm, 5);
+
+                       if (rule->granularity) {
+                               interval.from = sqlite3_column_int64(stm, 6);
+                               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 */
+                       break;
+               case SQLITE_DONE:
+                       break;
+               case SQLITE_ERROR:
+               default:
+                       result = RESOURCED_ERROR_DB_FAILED;
+                       break;
+               }
+       } while (rc == SQLITE_ROW);
+ out:
+       sqlite3_reset(stm);
+       return result;
+}
diff --git a/src/network/generic-netlink.c b/src/network/generic-netlink.c
new file mode 100644 (file)
index 0000000..a7f0e8e
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * 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 generic-netlink.c
+ *
+ * @desc User space code for ktgrabber logic
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <data_usage.h>
+#include <glib.h>
+#include <sys/socket.h> /*for netlink.h*/
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Ecore.h>
+
+#include "net-cls-cgroup.h"
+#include "const.h"
+#include "generic-netlink.h"
+#include "genl.h"
+#include "iface.h"
+#include "macro.h"
+#include "trace.h"
+#include "transmission.h"
+
+#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
+ */
+static int send_message(int fd, const char *message, int msg_len)
+{
+       struct sockaddr_nl nl_addr;
+       int ret = 0;
+
+       memset(&nl_addr, 0, sizeof(nl_addr));
+       nl_addr.nl_family = AF_NETLINK;
+
+       while ((ret =
+               sendto(fd, message, msg_len, 0, (struct sockaddr *)&nl_addr,
+                      sizeof(nl_addr))) < msg_len) {
+               if (ret <= 0 && errno != EAGAIN)
+                       return ret;
+               else if (errno == EAGAIN)
+                       continue;
+
+               message += ret;
+               msg_len -= ret;
+       }
+       return 0;
+}
+
+/*
+ * Probe the controller in genetlink to find the family id
+ * for the TRAF_STAT family
+ */
+
+uint32_t get_family_id(int sock, pid_t pid,
+       char *family_name)
+{
+       uint32_t family_id = 0;
+       uint32_t UNUSED group_id = get_family_group_id(sock, pid, family_name, NULL,
+               &family_id);
+       return family_id;
+}
+
+static int extract_group_id(const struct rtattr *rt_na, const char *group_name,
+       uint32_t *group_id)
+{
+       struct rtattr *multicast_group_family[__CTRL_ATTR_MCAST_GRP_MAX] = {0};
+       char *name;
+       struct rtattr *rt_nested;
+       int rt_len;
+
+       if (!rt_na)
+               return -EINVAL;
+
+       rt_nested = RTA_DATA(rt_na); /* nested */
+       rt_len = RTA_PAYLOAD(rt_na);
+
+       fill_attribute_list(multicast_group_family,
+               CTRL_ATTR_MCAST_GRP_MAX, rt_nested, rt_len);
+
+       if (!multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME] ||
+           !multicast_group_family[CTRL_ATTR_MCAST_GRP_ID])
+               return -EINVAL;
+
+       name = RTA_DATA(multicast_group_family[CTRL_ATTR_MCAST_GRP_NAME]);
+
+       if (strcmp(name, group_name))
+               return -EINVAL;
+
+       *group_id = *((__u32 *)RTA_DATA(
+               multicast_group_family[CTRL_ATTR_MCAST_GRP_ID]));
+       return RESOURCED_ERROR_NONE;
+}
+
+
+/*
+ * check subattribute CTRL_ATTR_MCAST_GROUPS
+ * if it exists we are dealing with broadcast generic
+ * netlink message
+ * message format is following
+ * CTRL_ATTR_MCAST_GROUPS
+ *  ATTR1
+ *    CTRL_ATTR_MCAST_GRP_NAME
+ *    CTRL_ATTR_MCAST_GRP_ID
+ *  ATTR2
+ *    CTRL_ATTR_MCAST_GRP_NAME
+ *    CTRL_ATTR_MCAST_GRP_ID
+ *  ...
+ */
+static uint32_t get_mcast_group_id(struct rtattr *mc_na, const char *group_name)
+{
+       struct rtattr *rt_na = RTA_DATA(mc_na); /* nested */
+       int rt_len = RTA_PAYLOAD(mc_na);
+       int i, ret;
+       uint32_t group_id;
+
+       struct rtattr *multicast_general_family[NESTED_MCAST_MAX + 1] = {0};
+
+       fill_attribute_list(multicast_general_family, NESTED_MCAST_MAX,
+                           rt_na, rt_len);
+
+       /* for each group */
+       for (i = 0; i < NESTED_MCAST_MAX; ++i) {
+               /* if this group is valid */
+               if (!multicast_general_family[i])
+                       continue;
+
+               ret = extract_group_id(multicast_general_family[i], group_name,
+                       &group_id);
+               if (ret == RESOURCED_ERROR_NONE)
+                       return group_id;
+       }
+
+       return 0;
+}
+
+uint32_t get_family_group_id(int sock, pid_t pid,
+                       char *family_name, char *group_name,
+                       uint32_t *family_id)
+{
+       struct genl family_req;
+       struct genl ans;
+
+       struct nlattr *na = 0;
+       int rep_len = 0, ret;
+       struct rtattr *general_family[__CTRL_ATTR_MAX] = {0};
+       struct rtattr *rt_na;
+       static uint32_t seq;
+
+       ret_value_msg_if(sock < 0, 0, "Please provide valid socket!");
+
+       family_req.n.nlmsg_type = GENL_ID_CTRL;
+       family_req.n.nlmsg_flags = NLM_F_REQUEST;
+       family_req.n.nlmsg_seq = seq++;
+       family_req.n.nlmsg_pid = pid;
+       family_req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       family_req.g.cmd = CTRL_CMD_GETFAMILY;
+
+       na = (struct nlattr *)GENLMSG_DATA(&family_req);
+       na->nla_type = CTRL_ATTR_FAMILY_NAME;
+
+       na->nla_len = strlen(family_name) + 1 + NLA_HDRLEN;
+       strcpy(NLA_DATA(na), family_name);
+
+       family_req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+       ret = send_message(sock, (char *)&family_req, family_req.n.nlmsg_len);
+
+       ret_value_msg_if(ret < 0, 0, "Failed to send GETFAMILY command");
+
+       rep_len = recv(sock, &ans, sizeof(ans), 0);
+
+       ret_value_msg_if(rep_len < 0, 0,
+               "Failed to receive answer for GETFAMILY command");
+
+       /* Validate response message */
+       if (!NLMSG_OK((&ans.n), rep_len)) {
+               _E("Invalid reply message\n");
+               return 0;
+       }
+
+       ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, 0,
+               "Invalid netlink message format");
+
+       rt_na = (struct rtattr *)GENLMSG_DATA(&ans);
+
+       fill_attribute_list(general_family, CTRL_ATTR_MAX, rt_na, rep_len);
+
+       /* family id for netlink is 16 bits long for multicast is 32 bit */
+       if (general_family[CTRL_ATTR_FAMILY_ID])
+               *family_id = *(__u16 *)RTA_DATA(
+                       general_family[CTRL_ATTR_FAMILY_ID]);
+
+       /* group name wasn't requested */
+       if (!group_name)
+               return 0;
+
+       if (!general_family[CTRL_ATTR_MCAST_GROUPS])
+               return 0;
+
+       return get_mcast_group_id(general_family[CTRL_ATTR_MCAST_GROUPS],
+               group_name);
+}
+
+#ifdef DEBUG_ENABLED
+static void show_result(const struct genl *ans)
+{
+       /*parse reply message */
+       struct nlattr *na = NULL;
+       char *result = NULL;
+
+       if (!ans) {
+               _D ("Please provide valid argument!");
+               return;
+       }
+
+       na = (struct nlattr *)GENLMSG_DATA(ans);
+       result = (char *)NLA_DATA(na);
+       if (result)
+               _D("Initialization result: %s\n", result);
+       else
+               _D("Failed to show initialization result!");
+}
+#else /* Release build */
+static void show_result(const struct genl *ans)
+{
+}
+#endif
+
+static resourced_ret_c send_common_cmd(int sock, const pid_t pid,
+       const uint32_t family_id, const __u8 cmd)
+{
+       struct genl ans;
+       int r;
+
+       ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
+               "Please provide valid socket!");
+
+       r = send_command(sock, pid, family_id, cmd);
+
+       ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
+               "Failed to send command");
+
+       /* Read message from kernel */
+       r = recv(sock, &ans, sizeof(ans), MSG_DONTWAIT);
+
+       ret_value_errno_msg_if(r < 0, RESOURCED_ERROR_FAIL,
+               "Cant receive message from kernel");
+
+       ret_value_msg_if(ans.n.nlmsg_type == NLMSG_ERROR, RESOURCED_ERROR_FAIL,
+               "Netlink format error");
+
+       ret_value_msg_if(!NLMSG_OK((&ans.n), r), RESOURCED_ERROR_FAIL,
+               "Invalid reply message received via Netlink");
+
+       show_result(&ans);
+       return RESOURCED_ERROR_NONE;
+}
+
+static resourced_ret_c run_net_activity(const __u8 cmd)
+{
+       int sock;
+       uint32_t family_id;
+       resourced_ret_c ret;
+       pid_t pid;
+       sock = create_netlink(NETLINK_GENERIC, 0);
+
+       ret_value_msg_if(sock < 0, RESOURCED_ERROR_FAIL,
+               "Failed to create netlink socket");
+       pid = getpid();
+       family_id = get_family_id(sock, pid, "NET_ACTIVITY");
+       if (!family_id) {
+               _E("Invalid family id number");
+               close(sock);
+               return RESOURCED_ERROR_FAIL;
+       }
+       /* send without handling response */
+       ret = send_command(sock, pid, family_id, cmd);
+
+       if (ret != RESOURCED_ERROR_NONE) {
+               ETRACE_ERRNO_MSG("Failed to send \
+                       net_activity command %u", cmd);
+               /* send_command return errno */
+               ret = RESOURCED_ERROR_FAIL;
+       }
+
+       close(sock);
+
+       return ret;
+}
+
+resourced_ret_c start_net_activity(void)
+{
+       return run_net_activity(NET_ACTIVITY_C_START);
+}
+
+resourced_ret_c stop_net_activity(void)
+{
+       return run_net_activity(NET_ACTIVITY_C_STOP);
+}
+
+
+void send_start(int sock, const pid_t pid, const int family_id)
+{
+       send_common_cmd(sock, pid, family_id, TRAF_STAT_C_START);
+}
+
+int send_command(int sock, const pid_t pid, const int family_id, __u8 cmd)
+{
+       struct genl req;
+       struct nlattr *na;
+       struct sockaddr_nl nladdr;
+       const char *message = "INIT";
+       const int mlength = sizeof(message) + 1;
+
+       ret_value_msg_if(sock < 0, RESOURCED_ERROR_NONE,
+               "Please provide valid socket!");
+
+       /* Send command needed */
+       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       req.n.nlmsg_type = family_id;
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_seq = 60;
+       req.n.nlmsg_pid = pid;
+       req.g.cmd = cmd;
+
+       /* compose message */
+       na = (struct nlattr *)GENLMSG_DATA(&req);
+       na->nla_type = 1;
+       na->nla_len = mlength + NLA_HDRLEN;     /* message length */
+       memcpy(NLA_DATA(na), message, mlength);
+       req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+       /* send message */
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+
+       return sendto(sock, (char *)&req, req.n.nlmsg_len, 0,
+                     (struct sockaddr *)&nladdr, sizeof(nladdr));
+}
+
+int send_restriction(int sock, const pid_t pid, const int family_id,
+                const u_int32_t classid, const int ifindex,
+                const enum traffic_restriction_type restriction_type,
+                const int send_limit, const int rcv_limit,
+                const int snd_warning_threshold, const int rcv_warning_threshold)
+{
+       struct genl req;
+       struct traffic_restriction rst = {
+               .sk_classid = classid,
+               .type = restriction_type,
+               .ifindex = ifindex,
+               .send_limit = send_limit,
+               .rcv_limit = rcv_limit,
+               .snd_warning_threshold = snd_warning_threshold,
+               .rcv_warning_threshold = rcv_warning_threshold,
+       };
+
+       struct nlattr *na;
+       struct sockaddr_nl nladdr;
+       int mlength = 0, r = 0;
+
+       if (sock < 0) {
+               _D("Can't use socket\n");
+               return -1;
+       }
+
+       /* Send command needed */
+       req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       req.n.nlmsg_type = family_id;
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_seq = 60;
+       req.n.nlmsg_pid = pid;
+       req.g.cmd = TRAF_STAT_C_SET_RESTRICTIONS;
+
+       /*compose message */
+       na = (struct nlattr *)GENLMSG_DATA(&req);
+       na->nla_type = TRAF_STAT_DATA_RESTRICTION;
+       mlength = sizeof(struct traffic_restriction);   /* * classid_count; */
+       na->nla_len = mlength + NLA_HDRLEN;
+
+       memcpy(NLA_DATA(na), &rst, sizeof(struct traffic_restriction));
+       req.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+       /*send message */
+
+       memset(&nladdr, 0, sizeof(nladdr));
+       nladdr.nl_family = AF_NETLINK;
+
+       /*use send_message */
+       r = sendto(sock, (char *)&req, req.n.nlmsg_len, 0,
+                  (struct sockaddr *)&nladdr, sizeof(nladdr));
+       _D("Restriction send to kernel, result: %d", r);
+       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)
+{
+       struct rtattr *na;
+       struct rtattr *attr_list[__RESTRICTION_NOTI_A_MAX] = {0};
+
+       int len = GENLMSG_PAYLOAD(&ans->n);
+
+       if (!restriction || !command)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (len <= 0)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       *command = ans->g.cmd;
+
+       /* parse reply message */
+       na = (struct rtattr *)GENLMSG_DATA(ans);
+
+       fill_attribute_list(attr_list, __RESTRICTION_NOTI_A_MAX - 1,
+               na, len);
+
+       ret_value_msg_if(!attr_list[RESTRICTION_A_CLASSID], RESOURCED_ERROR_FAIL,
+               "Restriction netlink message doesn't contain mandatory classid.");
+
+       restriction->sk_classid = *(uint32_t *)RTA_DATA(
+                       attr_list[RESTRICTION_A_CLASSID]);
+
+       if (attr_list[RESTRICTION_A_IFINDEX])
+               restriction->ifindex = *(int *)RTA_DATA(
+                       attr_list[RESTRICTION_A_IFINDEX]);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+enum net_activity_recv recv_net_activity(int sock, struct net_activity_info
+       *activity_info, const uint32_t net_activity_family_id)
+{
+       int ans_len, traffic_type;
+       struct traffic_event *event;
+       struct nlattr *na = 0;
+       struct genl ans;
+       uint32_t family_id;
+
+       ans_len = recv(sock, &ans, sizeof(ans),
+                       MSG_DONTWAIT);
+
+       if (ans_len <= 0 || !NLMSG_OK((&ans.n), ans_len)) {
+               ETRACE_ERRNO_MSG("Failed to read netlink socket %d",
+                       ans_len);
+               return RESOURCED_NET_ACTIVITY_STOP;
+       }
+
+       _D("Reading multicast netlink message len %d", ans_len);
+
+       family_id = netlink_get_family(&ans);
+
+       if (family_id != net_activity_family_id) {
+               _D("Received family_id %d", family_id);
+               return RESOURCED_NET_ACTIVITY_CONTINUE;
+       }
+
+       na = (struct nlattr *)GENLMSG_DATA(&ans);
+
+       traffic_type = na->nla_type;
+
+       event = (struct traffic_event *) NLA_DATA(na);
+       activity_info->type = traffic_type;
+       activity_info->bytes = event->bytes;
+       activity_info->iftype = get_iftype(event->ifindex);
+       activity_info->appid = get_app_id_by_classid(event->sk_classid, true);
+
+       return RESOURCED_NET_ACTIVITY_OK;
+}
diff --git a/src/network/iface-cb.c b/src/network/iface-cb.c
new file mode 100644 (file)
index 0000000..6f2457f
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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 iface-cb.c
+ *
+ * @desc Network interface callbacks entity
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "macro.h"
+#include "datausage-common.h"
+#include "restriction-handler.h"
+#include "settings.h"
+#include "storage.h"
+#include "trace.h"
+
+#include <Ecore.h>
+#include <linux/genetlink.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/socket.h> /*for netlink.h*/
+#include <sys/types.h>
+#include <unistd.h>
+
+#define ADDR_EVENT_BUF_LEN 4096
+static int iface_fd;
+
+static iface_callbacks *ifcallbacks;
+static Ecore_Fd_Handler *iface_ecore_fd_handler;
+
+static iface_callbacks *create_iface_callback(void)
+{
+       iface_callbacks *callbacks = NULL;
+       gpointer callback_data = create_restriction_callback();
+
+       if (callback_data)
+               callbacks = g_list_prepend(callbacks, callback_data);
+       callback_data = create_iface_storage_callback();
+       if (callback_data)
+               callbacks = g_list_prepend(callbacks, callback_data);
+       callback_data = create_counter_callback();
+       if (callback_data)
+               callbacks = g_list_prepend(callbacks, callback_data);
+
+       return callbacks;
+}
+
+static void _iface_up_iter(gpointer data, gpointer user_data)
+{
+       iface_callback *arg = (iface_callback *)data;
+       uint32_t ifindex = *(uint32_t *) (user_data);
+       if (arg && arg->handle_iface_up)
+               arg->handle_iface_up(ifindex);
+}
+
+static void _iface_down_iter(gpointer data, gpointer user_data)
+{
+       iface_callback *arg = (iface_callback *)data;
+       uint32_t ifindex = *(uint32_t *)(user_data);
+       if (arg && arg->handle_iface_down)
+               arg->handle_iface_down(ifindex);
+}
+
+static void process_nlh(int len, const struct nlmsghdr *nlh,
+                               iface_callbacks *arg)
+{
+       if (!arg) {
+               _D("Please provide valid argument!");
+               return;
+       }
+
+       for (; (NLMSG_OK(nlh, len)) &&
+               (nlh->nlmsg_type != NLMSG_DONE);
+               nlh = NLMSG_NEXT(nlh, len)) {
+               if (nlh->nlmsg_type != RTM_NEWADDR
+                       && nlh->nlmsg_type != RTM_DELADDR)
+                       continue;
+
+               struct ifaddrmsg *ifa =
+                       (struct ifaddrmsg *) NLMSG_DATA(nlh);
+               struct rtattr *rth = IFA_RTA(ifa);
+               int rtl = IFA_PAYLOAD(nlh);
+
+               for (; rtl && RTA_OK(rth, rtl);
+                       rth = RTA_NEXT(rth, rtl)) {
+                       if (rth->rta_type != IFA_LOCAL)
+                               continue;
+
+                       if (nlh->nlmsg_type == RTM_NEWADDR) {
+                               init_iftype();
+                               return g_list_foreach(arg, _iface_up_iter,
+                                       &(ifa->ifa_index));
+
+                       } else if (nlh->nlmsg_type == RTM_DELADDR) {
+                               g_list_foreach(arg, _iface_down_iter,
+                                       &(ifa->ifa_index));
+                               /* network delete hooks require old information,
+                                * for example for get_iftype by ifindex */
+                               init_iftype();
+                               return;
+                       }
+               }
+       }
+}
+
+static Eina_Bool iface_func_cb(void *user_data, Ecore_Fd_Handler *fd_handler)
+{
+       char buff[ADDR_EVENT_BUF_LEN];
+       struct nlmsghdr *nlh;
+       iface_callbacks *localiarg = (iface_callbacks *)user_data;
+       int fd;
+       int len;
+
+       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_RENEW;
+       }
+
+       fd = ecore_main_fd_handler_fd_get(fd_handler);
+       if (fd < 0) {
+               _E("ecore_main_fd_handler_fd_get error");
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       len = read(fd, buff, ADDR_EVENT_BUF_LEN);
+       if (len < 0)  {
+               _E("socket read error");
+               return ECORE_CALLBACK_RENEW;
+       }
+
+       nlh = (struct nlmsghdr *)buff;
+       process_nlh(len, nlh, localiarg);
+
+       return ECORE_CALLBACK_RENEW;
+}
+
+static int iface_func_init()
+{
+       struct sockaddr_nl addr = {0};
+       int sock, error = 0, on;
+
+       sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+       if (sock == -1) {
+               _E("Error creating NETLINK_ROUTE socket");
+               error = errno;
+               goto handle_error;
+       }
+
+       addr.nl_family = AF_NETLINK;
+       addr.nl_groups = RTMGRP_IPV4_IFADDR;
+/* Enable address reuse */
+       on = 1;
+       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
+               _E("Error setsockopt");
+               error = errno;
+               goto release_socket;
+       }
+
+       if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+               _E("Error bind socket");
+               error = errno;
+               goto release_socket;
+       }
+
+       _D("Socket created successfully\n");
+
+       return sock;
+
+release_socket:
+       close(sock);
+handle_error:
+       return -error;
+}
+
+static void apply_iface_options(void)
+{
+       resourced_options options = { 0 };
+
+       load_options(&options);
+       set_wifi_allowance(options.wifi);
+       set_datacall_allowance(options.datacall);
+}
+
+int resourced_iface_init(void)
+{
+       ifcallbacks = create_iface_callback();
+       _D("Initialize network interface callbacks\n");
+       ret_value_msg_if(ifcallbacks == NULL, RESOURCED_ERROR_FAIL,
+                        "Error create network interface callbacks");
+       iface_fd = iface_func_init();
+       ret_value_msg_if(iface_fd < 0, RESOURCED_ERROR_FAIL,
+                        "Can not listen network interface changes %d",
+                        iface_fd);
+       iface_ecore_fd_handler = ecore_main_fd_handler_add(
+               iface_fd, ECORE_FD_READ, iface_func_cb,
+               (void *)ifcallbacks, NULL, NULL);
+       ret_value_msg_if(iface_ecore_fd_handler == NULL, RESOURCED_ERROR_FAIL,
+                        "Failed to add iface callbacks\n");
+       apply_iface_options();
+       return RESOURCED_ERROR_NONE;
+}
+
+void resourced_iface_finalize(void)
+{
+       _D("Finalize network interface callbacks\n");
+       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
new file mode 100644 (file)
index 0000000..5823bfd
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * 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 iface.c
+ *
+ * @desc Utility for working with network interfaces
+ */
+
+
+#include <errno.h>
+#include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+#include <linux/un.h>
+#include <net/if.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "config-parser.h"
+#include "const.h"
+#include "iface.h"
+#include "macro.h"
+#include "trace.h"
+
+#define NET_INTERFACE_NAMES_FILE "/etc/resourced/network.conf"
+#define IFACES_TYPE_SECTION "IFACES_TYPE"
+
+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 const char *UEVENT_FMT = "/sys/class/net/%s/uevent";
+static const char *DEVTYPE_KEY = "DEVTYPE";
+static const char *WIRED_VALUE = "gadget";
+static const char *WIFI_VALUE = "wlan";
+static const char *BLUETOOTH_VALUE = "bluetooth";
+static const char *DATACALL_VALUE = "datacall";
+static const char *ALL_NET_IFACE_VALUE = "all";
+static const char *UEVENT_DELIM = "=\n";
+
+static GSList *ifnames_relations;
+
+struct iface_relation {
+       resourced_iface_type iftype;
+       char ifname[MAX_NAME_LENGTH];
+};
+
+static gint compare_int(gconstpointer a, gconstpointer b,
+       gpointer UNUSED userdata)
+{
+       if (a == b)
+               return 0;
+       else if (a > b)
+               return 1;
+       return -1;
+}
+
+static GTree *create_iface_tree(void)
+{
+       return g_tree_new_full(compare_int,
+               NULL, NULL, free);
+}
+
+static void put_iftype_to_tree(GTree *iftypes_tree, int ifindex, int iftype)
+{
+       gpointer new_value;
+
+       ret_msg_if(!iftypes_tree, "Please provide valid argument!");
+       new_value = (gpointer)malloc(sizeof(int));
+       if (!new_value) {
+               _E("Malloc of put_iftype_to_tree failed\n");
+               return;
+       }
+       *(int *)new_value = iftype;
+       g_tree_replace(iftypes_tree, (gpointer)ifindex, new_value);
+}
+
+static void put_ifname_to_tree(GTree *ifnames_tree, 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;
+       }
+       strncpy(new_value, ifname, name_len);
+
+       if (!ifnames_tree) {
+               free(new_value);
+               _E("Please provide valid argument!");
+               return;
+       }
+       g_tree_replace(ifnames_tree, (gpointer)iftype, new_value);
+}
+
+static resourced_iface_type get_iftype_from_tree(GTree *iftypes_tree, int ifindex)
+{
+       resourced_iface_type ret = RESOURCED_IFACE_UNKNOWN;
+       gpointer table_value;
+
+       ret_value_msg_if(!iftypes_tree, ret, "Please provide valid argument!");
+
+       pthread_rwlock_rdlock(&iftypes_guard);
+       table_value = g_tree_lookup(iftypes_tree, (gpointer)ifindex);
+       pthread_rwlock_unlock(&iftypes_guard);
+       if (table_value != NULL)
+               ret = *(int *)table_value;
+
+       return ret;
+}
+
+static void free_iftypes_tree(GTree *iftypes_tree)
+{
+       g_tree_destroy(iftypes_tree);
+}
+
+static void iface_stat_allowance(void)
+{
+       size_t i;
+       for (i = 0; i < ARRAY_SIZE(iface_stat); ++i)
+               iface_stat[i] = 1;
+}
+
+static resourced_iface_type get_predefined_iftype(const char *ifname)
+{
+       struct iface_relation *relation;
+       GSList *iter;
+       gslist_for_each_item(iter, ifnames_relations) {
+               relation = (struct iface_relation *)iter->data;
+                       if (strstr(ifname, relation->ifname))
+                               return relation->iftype;
+       }
+       _D("Even in predefined interface name list, interface types wasn't "
+          " find for %s", ifname);
+       return RESOURCED_IFACE_UNKNOWN;
+}
+
+static resourced_iface_type read_iftype(const char *iface)
+{
+       char buffer[UNIX_PATH_MAX];
+       char *key_buffer;
+       char *value_buffer;
+       FILE *uevent;
+       resourced_iface_type ret = RESOURCED_IFACE_UNKNOWN;
+
+       snprintf(buffer, UNIX_PATH_MAX, UEVENT_FMT, iface);
+       uevent = fopen(buffer, "r");
+
+       if (!uevent)
+               return ret;
+
+       while (!feof(uevent)) {
+               if (fgets(buffer, UNIX_PATH_MAX, uevent) == NULL)
+                       break;
+               key_buffer = strtok(buffer, UEVENT_DELIM);
+               value_buffer = strtok(NULL, UEVENT_DELIM);
+               if (strcmp(key_buffer, DEVTYPE_KEY) != 0)
+                       continue;
+               ret = convert_iftype(value_buffer);
+               break;
+       }
+
+       fclose(uevent);
+
+       /* work around, in case of missing DEVTYPE field */
+       if (ret == RESOURCED_IFACE_UNKNOWN)
+               ret = get_predefined_iftype(iface);
+
+       return ret;
+}
+
+static void reset_tree(GTree *new, GTree **old,
+       pthread_rwlock_t *guard)
+{
+       GTree *release = *old;
+
+       pthread_rwlock_wrlock(guard);
+       *old = new;
+       pthread_rwlock_unlock(guard);
+       if (release)
+               free_iftypes_tree(release);
+}
+
+bool is_address_exists(const char *name)
+{
+#ifdef SIOCDIFADDR
+       struct ifreq ifr;
+       static int fd;
+       if (!fd)
+               fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+       memset(&ifr, 0, sizeof(struct ifreq));
+       strcpy(ifr.ifr_name, name);
+       return ioctl(fd, SIOCGIFADDR, &ifr) == 0;
+#endif /* SIOCDIFADDR */
+       return true;
+}
+
+static int fill_ifaces_relation(struct parse_result *result,
+                               void UNUSED *user_data)
+{
+       struct iface_relation *relation;
+       if (strcmp(result->section, IFACES_TYPE_SECTION))
+               return RESOURCED_ERROR_NONE;
+
+       relation = (struct iface_relation *)malloc(sizeof(struct iface_relation));
+
+       ret_value_msg_if(relation == NULL, RESOURCED_ERROR_NONE,
+               "Failed to allocated memory!");
+
+       relation->iftype = convert_iftype(result->name);
+       STRING_SAVE_COPY(relation->ifname, result->value);
+
+       ifnames_relations = g_slist_prepend(ifnames_relations, relation);
+       return RESOURCED_ERROR_NONE;
+}
+
+int init_iftype(void)
+{
+       int i, ret;
+       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",
+                       errno, strerror(errno));
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       if (!ifnames_relations) {
+               ret = config_parse(NET_INTERFACE_NAMES_FILE,
+                                  fill_ifaces_relation, NULL);
+               if (ret != 0)
+                       _D("Can't parse config file %s",
+                          NET_INTERFACE_NAMES_FILE);
+       }
+
+       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);
+               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);
+               _D("ifname %s, ifype %d", ids[i].if_name, iftype);
+       }
+
+       /* Do not forget to free the memory */
+       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_relations, free);
+}
+
+resourced_iface_type convert_iftype(const char *buffer)
+{
+       if (!buffer) {
+               _E("Malloc of answer_get_stat failed\n");
+               return RESOURCED_IFACE_UNKNOWN;
+       }
+
+       if (strcmp(buffer, DATACALL_VALUE) == 0)
+               return RESOURCED_IFACE_DATACALL;
+
+       if (strcmp(buffer, WIFI_VALUE) == 0)
+               return RESOURCED_IFACE_WIFI;
+
+       if (strcmp(buffer, BLUETOOTH_VALUE) == 0)
+               return RESOURCED_IFACE_BLUETOOTH;
+
+       if (strcmp(buffer, WIRED_VALUE) == 0)
+               return RESOURCED_IFACE_WIRED;
+       if (strcmp(buffer, ALL_NET_IFACE_VALUE) == 0)
+               return RESOURCED_IFACE_ALL;
+       return RESOURCED_IFACE_UNKNOWN;
+}
+
+int is_allowed_ifindex(int ifindex)
+{
+       return iface_stat[get_iftype(ifindex)];
+}
+
+resourced_iface_type get_iftype(int ifindex)
+{
+       return get_iftype_from_tree(iftypes, ifindex);
+}
+
+static gboolean print_ifname(gpointer key, gpointer value, gpointer data)
+{
+       _D("ifname %s", (char *)value);
+       return FALSE;
+}
+
+static char *get_ifname_from_tree(GTree *ifnames_tree, int iftype)
+{
+       char *ret = NULL;
+
+       ret_value_msg_if(!ifnames_tree, 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);
+
+       return ret;
+}
+
+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;
+}
+
+static bool is_only_loopback(GTree *iftypes_tree)
+{
+       int nodes = g_tree_nnodes(iftypes_tree);
+       int res = 0;
+
+       if (nodes > 1)
+               return false;
+
+       g_tree_foreach(iftypes_tree, search_loopback, &res);
+       return res;
+}
+
+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)
+               empty_func(data);
+
+       pthread_rwlock_unlock(&iftypes_guard);
+}
+
+void set_wifi_allowance(const resourced_option_state wifi_option)
+{
+       iface_stat[RESOURCED_IFACE_WIFI] = wifi_option == RESOURCED_OPTION_ENABLE ? 1 : 0;
+}
+
+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/network/include/counter-process.h b/src/network/include/counter-process.h
new file mode 100644 (file)
index 0000000..8ef555e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file counter-process.h
+ *
+ * @desc Counter process entity
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef _RESOURCED_DATAUSAGE_COUNTER_PROCESS_H
+#define _RESOURCED_DATAUSAGE_COUNTER_PROCESS_H
+
+#include "counter.h"
+
+int resourced_init_counter_func(struct counter_arg *carg);
+
+void resourced_finalize_counter_func(struct counter_arg *carg);
+
+#endif /* _RESOURCED_DATAUSAGE_COUNTER_PROCESS_H */
diff --git a/src/network/include/counter.h b/src/network/include/counter.h
new file mode 100644 (file)
index 0000000..3e89fdc
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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: counter.h
+ *
+ *  @desc Entity for working with datausage counter.
+ *        In plans place to counter.c main counting procedure from main.c
+ */
+
+
+#ifndef _RESOURCED_DATAUSAGE_COUNTER_H
+#define _RESOURCED_DATAUSAGE_COUNTER_H
+
+#include "app-stat.h"
+#include "config.h"
+#include "daemon-options.h"
+
+#include <Ecore.h>
+
+struct counter_arg {
+       int sock;
+       int ans_len;
+#ifndef CONFIG_DATAUSAGE_NFACCT
+       pid_t pid;
+       int family_id_stat;
+       int family_id_restriction;
+#else
+       GTree *nf_cntrs;
+       int initiate;
+       int noti_fd;
+       Ecore_Fd_Handler *noti_fd_handler;
+#endif
+       struct daemon_opts *opts;
+       struct application_stat_tree *result;
+       traffic_stat_tree *in_tree;
+       traffic_stat_tree *out_tree;
+       Ecore_Timer *ecore_timer;
+       Ecore_Fd_Handler *ecore_fd_handler;
+       Ecore_Timer *store_result_timer;
+};
+
+/**
+ * @desc Reschedule existing traffic counter function
+ *  Rescheduling logic is following, we will postpone
+ *  execution on delay seconds.
+ */
+void reschedule_count_timer(const struct counter_arg *carg, const double delay);
+
+struct counter_arg *init_counter_arg(struct daemon_opts *opts);
+
+void finalize_carg(struct counter_arg *carg);
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+GTree *create_nfacct_tree(void);
+#endif /* CONFIG_DATAUSAGE_NFACCT */
+
+#endif /* _RESOURCED_NETWORK_COUNTING_H_ */
+
+
diff --git a/src/network/include/database.h b/src/network/include/database.h
new file mode 100644 (file)
index 0000000..1390d35
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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: database.h
+ *
+ *  @desc Performance management API. Database helper
+ *  @version 1.0
+ *
+ *  Created on: Jun 29, 2012
+ */
+
+#include <sqlite3.h>
+
+#ifndef TRESOURCED_DATABASE_H_
+#define TRESOURCED_DATABASE_H_
+
+sqlite3 *resourced_get_database(void);
+
+/**
+ * @desc Initialize DB and DB statement
+ * only once time
+ */
+void libresourced_db_initialize_once(void);
+
+#endif /* TRESOURCED_DATABASE_H_ */
diff --git a/src/network/include/datausage-common.h b/src/network/include/datausage-common.h
new file mode 100644 (file)
index 0000000..49b8cf9
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file netstat-common.h
+ *
+ * @desc Datausage module control structures
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef __RESOURCED_NETSTAT_COMMON_H__
+#define __RESOURCED_NETSTAT_COMMON_H__
+
+#include <stdint.h>
+
+#include <resourced.h>
+
+#include "iface.h"
+
+enum netstat_control_type {
+       NET_CTRL_TYPE_UNKNOWN,
+       JOIN_NET_CLS,
+       NET_CTRL_TYPE_LAST_ELEM,
+};
+
+struct netstat_data_type
+{
+       enum netstat_control_type op_type;
+       uint32_t *args;
+};
+
+/**
+ * @brief It creates an appropriate cgroup,
+ *   it generates classid for the network performance control.
+ *   This function uses module's control callback interface to
+ *   invoke join_app_performance
+ * @param app_id[in] - application identifier, it's package name now
+ * @param pid - pid to put in to cgroup, or self pid of 0
+ * @return 0 if success or error code
+ */
+resourced_ret_c join_net_cls(const char *app_id, const pid_t pid);
+
+iface_callback *create_counter_callback(void);
+
+struct nfacct_rule;
+void keep_counter(struct nfacct_rule *counter);
+
+#endif /* __RESOURCED_NETSTAT_COMMON_H__ */
diff --git a/src/network/include/datausage-foreach.h b/src/network/include/datausage-foreach.h
new file mode 100644 (file)
index 0000000..aa4c9f4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 datausage-foreach.h
+ *
+ *  @desc Data usage foreach initialization/deinitialization functions.
+ *
+ *  Created on: Jul 17, 2012
+ */
+
+#ifndef _RESOURCED_SRC_DATAUSAGE_H_
+#define _RESOURCED_SRC_DATAUSAGE_H_
+
+int init_datausage_foreach(sqlite3 *db);
+void finalize_datausage_foreach(void);
+
+#endif /* _RESOURCED_SRC_DATAUSAGE_H_ */
+
diff --git a/src/network/include/datausage-quota-processing.h b/src/network/include/datausage-quota-processing.h
new file mode 100644 (file)
index 0000000..016520a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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: datausage-quota-processing.h
+ *
+ *  @desc Entity for working with quotas
+ *  @version 2.0
+ *
+ *  Created on: Aug 08, 2012
+ */
+
+#ifndef _TRESOURCED_DATAUSAGE_QUOTA_PROCESSING_H_
+#define _TRESOURCED_DATAUSAGE_QUOTA_PROCESSING_H_
+
+#include <sqlite3.h>
+
+#include "app-stat.h"
+#include "resourced.h"
+
+/*
+ * Store data in effective quota
+ */
+void flush_quota_table(void);
+
+/*
+ * 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);
+
+/*
+ * Finish working with quotas
+ */
+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);
+
+#endif /* _TRESOURCED_DATAUSAGE_QUOTA_PROCESSING_H_ */
diff --git a/src/network/include/datausage-quota.h b/src/network/include/datausage-quota.h
new file mode 100644 (file)
index 0000000..d20cb41
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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: datausage-quota.h
+ *
+ *  @desc Performance management API
+ *  @version 1.0
+ *
+ *  Created on: Jul 31, 2012
+ */
+
+#ifndef TRESOURCED_DATAUSAGE_QUOTA_H_
+#define TRESOURCED_DATAUSAGE_QUOTA_H_
+
+#include <sqlite3.h>
+
+#define RESOURCED_NEW_LIMIT_PATH "db/private/resourced/new_limit"
+#define RESOURCED_DELETE_LIMIT_PATH "db/private/resourced/delete_limit"
+
+int init_datausage_quota(sqlite3 *db);
+
+void finalize_datausage_quota(void);
+
+#endif /* TRESOURCED_DATAUSAGE_QUOTA_H_ */
similarity index 55%
rename from src/common/cpu-common.c
rename to src/network/include/datausage-reset.h
index b075603..9393238 100644 (file)
  *
  */
 
-/**
- * @file cpu-common.c
- * @desc Implement lowmem API for external module
+
+/*
+ * @file reset.h
  *
  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  */
 
-#include "module.h"
-#include "resourced.h"
-#include "cpu-common.h"
-
-static const struct module_ops *cpu;
-static int cpu_module;
-
-void cpu_find_module()
-{
-       if (!cpu_module) {
-               cpu = find_module("cpu");
-               cpu_module = 1;
-       }
-}
+#ifndef _RESOURCED_RESET_H_
+#define _RESOURCED_RESET_H_
 
-int cpu_control(enum cpu_control_type type, pid_t pid)
-{
-       struct cpu_data_type l_data;
-       int ret = RESOURCED_ERROR_NONE;
-
-       if (!cpu) {
-               cpu_find_module();
-               if (!cpu)
-                       return ret;
-       }
-
-       l_data.control_type = type;
-       l_data.pid = pid;
-
-       if (cpu->control)
-               ret = cpu->control(&l_data);
-       return ret;
-}
+/**
+ * @brief Data usage clearing procedures.
+ * This function deinitializing sqlite3 statements
+ */
+void finalize_datausage_reset(void);
 
+#endif /* _RESOURCED_RESET_H_ */
diff --git a/src/network/include/datausage-restriction.h b/src/network/include/datausage-restriction.h
new file mode 100644 (file)
index 0000000..e1ee46a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 restriction.h
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef _RESOURCED_RESTRICTION_H_
+#define _RESOURCED_RESTRICTION_H_
+
+#include <sqlite3.h>
+#include "resourced.h"
+#include "data_usage.h"
+#include "transmission.h"
+
+void finalize_datausage_restriction(void);
+
+/**
+ * @desc Update restriction database
+ **/
+resourced_ret_c update_restriction_db(
+       const char *app_id, const resourced_iface_type iftype,
+       const int rcv_limit, const int snd_limit,
+       const resourced_restriction_state rst_state,
+       const int quota_id,
+       const resourced_roaming_type roaming);
+
+/**
+ * @desc Get restriction info from database
+ *     Now it filles only quota_id, send_limit,
+ *     rcv_limit, rst_state
+ *
+ * @param app_id - binpath database field, currently pkgid
+ * @param iftype - iftype database field
+ **/
+resourced_ret_c get_restriction_info(const char *app_id,
+                               const resourced_iface_type iftype,
+                               resourced_restriction_info *rst);
+
+resourced_ret_c process_kernel_restriction(
+       const u_int32_t classid,
+       const resourced_net_restrictions *rst,
+       const enum traffic_restriction_type rst_type);
+
+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);
+
+resourced_ret_c remove_restriction_local(const char *app_id,
+                                        const resourced_iface_type iftype);
+
+resourced_ret_c exclude_restriction_local(const char *app_id,
+                                         const int quota_id,
+                                         const resourced_iface_type iftype);
+
+#endif /* _RESOURCED_RESTRICTION_H_ */
diff --git a/src/network/include/datausage-vconf-callbacks.h b/src/network/include/datausage-vconf-callbacks.h
new file mode 100644 (file)
index 0000000..2208c0e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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: datausage-vconf-callbacks.h
+ *
+ *  @desc Add datausage callback functions to vconf
+ *
+ */
+
+#ifndef _RESOURCED_DATAUSAGE_VCONF_CALLBACKS_H
+#define _RESOURCED_DATAUSAGE_VCONF_CALLBACKS_H
+
+#include "counter.h"
+
+void resourced_add_vconf_datausage_cb(struct counter_arg *carg);
+
+void resourced_remove_vconf_datausage_cb(void);
+
+#endif /* _RESOURCED_DATAUSAGE_VCONF_CALLBACKS_H */
diff --git a/src/network/include/datausage-vconf-common.h b/src/network/include/datausage-vconf-common.h
new file mode 100644 (file)
index 0000000..5d23d76
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+enum restriction_state {
+       RESTRICTION_STATE_INIT = -1,
+       RESTRICTION_STATE_UNSET,
+       RESTRICTION_STATE_SET,
+};
+
+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/errors.h b/src/network/include/errors.h
new file mode 100644 (file)
index 0000000..59c256a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 2012 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: errors.h
+ *
+ *  @desc Internal error codes.
+ *  @version 1.0
+ *
+ */
+
+#ifndef _GRABBER_CONTROL_ERRORS_H_
+#define _GRABBER_CONTROL_ERRORS_H_
+
+enum {
+       ERROR_CANT_CREATE_NL_SOCKET = 1,
+       ERROR_UPDATE_PID_LIST = 2,
+       ERROR_UPDATE_CLASSIDS_LIST = 3,
+};
+
+#endif /*_GRABBER_CONTROL_ERRORS_H_ */
diff --git a/src/network/include/generic-netlink.h b/src/network/include/generic-netlink.h
new file mode 100644 (file)
index 0000000..975db67
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file generic-netlink.h
+ * @desc Helper function for making kernel request and process response
+ **/
+
+#ifndef _GRABBER_CONTROL_KERNEL_GENERIC_NETLINK_H_
+#define _GRABBER_CONTROL_KERNEL_GENERIC_NETLINK_H_
+
+#include "counter.h"
+#include "genl.h"
+#include "nl-helper.h"
+
+#include <unistd.h>
+#include <linux/genetlink.h>
+#include <linux/rtnetlink.h>
+
+enum net_activity_recv {
+       RESOURCED_NET_ACTIVITY_OK,
+       RESOURCED_NET_ACTIVITY_STOP,
+       RESOURCED_NET_ACTIVITY_CONTINUE,
+};
+
+netlink_serialization_command *netlink_create_command(
+       struct netlink_serialization_params *params);
+
+uint32_t get_family_id(int sock, pid_t pid, char *family_name);
+
+/**
+ * @desc get id for multicasted generic netlink messages
+ *     only one multicast group is supported per family id now.
+ *     This function also gets family id, due it comes with the
+ *     same answer as a multicast generic netlink message.
+ */
+uint32_t get_family_group_id(int sock, pid_t pid,
+                       char *family_name, char *group_name,
+                       uint32_t *family_id);
+
+/**
+ * @desc Extracts family id from answer
+ *     accepts opaque pointer
+ **/
+uint32_t netlink_get_family(struct genl *nl_ans);
+
+/**
+ * @desc This function sends to kernel command to start
+ *     network activity reporting. This function creats
+ *     and closes socket itself.
+ **/
+resourced_ret_c start_net_activity(void);
+
+/**
+ * @desc Stop network activity @see start_net_activity
+ **/
+resourced_ret_c stop_net_activity(void);
+
+struct net_activity_info;
+
+/**
+ * @desc Receive and fill activity info from netlink socket.
+ *     Received activity_info should contain the same family_id as
+ *     net_activity_family_id
+ */
+enum net_activity_recv recv_net_activity(int sock, struct net_activity_info
+       *activity_info, const uint32_t net_activity_family_id);
+
+/**
+ * @desc Extracts family id from answer
+ *     accepts opaque pointer
+ **/
+uint32_t netlink_get_family(struct genl *nl_ans);
+
+void send_start(int sock, const pid_t pid, const int family_id);
+
+int send_command(int sock, const pid_t pid, const int family_id, uint8_t cmd);
+
+int send_restriction(int sock, const pid_t pid, const int family_id,
+                    const u_int32_t classid, const int ifindex,
+                    const enum traffic_restriction_type restriction_type,
+                    const int send_limit,
+                    const int rcv_limit,
+                    const int snd_warning_threshold,
+                    const int rcv_warning_threshold);
+
+resourced_ret_c process_netlink_restriction_msg(const struct genl *ans,
+       struct traffic_restriction *restriction, uint8_t *command);
+
+#endif /*_GRABBER_CONTROL_KERNEL_GENERIC_NETLINK_H_*/
similarity index 53%
rename from src/common/lowmem-common.c
rename to src/network/include/iface-cb.h
index 2c0da4d..3889e53 100644 (file)
  */
 
 /**
- * @file lowmem-common.c
- * @desc Implement lowmem API for external module
+ * @file iface-cb.h
+ *
+ * @desc Network interface callbacks entity
  *
  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  */
 
-#include "module.h"
-#include "resourced.h"
-#include "lowmem-common.h"
-
-static const struct module_ops *lowmem;
-static int lowmem_module;
-
-void lowmem_find_module()
-{
-       if (!lowmem_module) {
-               lowmem = find_module("lowmem");
-               lowmem_module = 1;
-       }
-}
-
-int lowmem_control(enum lowmem_control_type type, unsigned long *args)
-{
-       struct lowmem_data_type l_data;
-       int ret = RESOURCED_ERROR_NONE;
+#ifndef _RESOURCED_CALLBACKS_NET_IFACE_H_
+#define _RESOURCED_CALLBACKS_NET_IFACE_H_
 
-       if (!lowmem) {
-               lowmem_find_module();
-               if (!lowmem)
-                       return ret;
-       }
+int resourced_iface_init(void);
 
-       l_data.control_type = type;
-       l_data.args = args;
+void resourced_iface_finalize(void);
 
-       if (lowmem->control)
-               ret = lowmem->control(&l_data);
-       return ret;
-}
+#endif /* _RESOURCED_CALLBACKS_NET_IFACE_H_ */
diff --git a/src/network/include/iface.h b/src/network/include/iface.h
new file mode 100644 (file)
index 0000000..3e70d0e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 iface.h
+ *
+ * @desc Utility for working with network interfaces
+ */
+
+#ifndef TRESOURCED_LIBS_NET_IFACE_H_
+#define TRESOURCED_LIBS_NET_IFACE_H_
+
+#include <glib.h>
+#include <stdbool.h>
+
+#include "data_usage.h"
+
+/**
+ * @desc Storage now create an instance of this structure
+ */
+typedef struct {
+       void(*handle_iface_up)(int ifindex);
+       void(*handle_iface_down)(int ifindex);
+} iface_callback;
+
+int init_iftype(void);
+void finalize_iftypes(void);
+
+int is_allowed_ifindex(int ifindex);
+
+resourced_iface_type get_iftype(int ifindex);
+char *get_iftype_name(resourced_iface_type iftype);
+bool is_address_exists(const char *name);
+
+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);
+
+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 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
new file mode 100644 (file)
index 0000000..70eec15
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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: net-cls-cgroup.h
+ *
+ *  @desc Performance management daemon. Helper function
+ *             for working with classid table.
+ *  @version 1.0
+ *
+ */
+
+
+#ifndef _RESOURCED_NET_CLS_CGROUP_H_
+#define _RESOURCED_NET_CLS_CGROUP_H_
+
+#include <sys/types.h>
+#include <glib.h>
+#include <stdbool.h>
+
+#include "resourced.h"
+
+typedef GArray int_array;
+
+/**
+ * @desc Get all pids from cgroup
+ *     Should be invoked after update_classids
+ * @return array, you should free it
+ */
+int_array *get_monitored_pids(void);
+
+/**
+ * @desc update class id - pid table. At present one pid per classid.
+ */
+int update_classids(void);
+
+/**
+ * @desc Get appid from classid task table. At present it is package name.
+ */
+char *get_app_id_by_pid(const pid_t pid);
+char *get_app_id_by_classid(const u_int32_t classid, const bool update_state);
+
+/**
+ * @desc take classid from net_cls cgroup by appid
+ *     This function converts appid to pkgname.
+ * @param pkg_name - name of the cgroup
+ * @param create - in case of true - create cgroup if it's not exists
+ * @return classid
+ */
+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
+ */
+u_int32_t get_classid_by_pkg_name(const char *pkg_name, int create);
+
+/**
+ * @desc Make net_cls cgroup and put in it the given pid and
+ * generated classid.
+ * If cgroup alreay exists function just put pid in it.
+ * @param pid - process, that will be added to cgroup pkg_name,
+ * @param pkg_name - package name.
+ */
+resourced_ret_c make_net_cls_cgroup_with_pid(const int pid,
+       const char *pkg_name);
+
+#endif /*_RESOURCED_NET_CLS_CGROUP_H_*/
diff --git a/src/network/include/netlink-restriction.h b/src/network/include/netlink-restriction.h
new file mode 100644 (file)
index 0000000..1df4f03
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 net-restriction.h
+ *  @desc Performance management API. Network restriction.
+ *  @version 1.0
+ *
+ *  Created on: Jun 18, 2012
+ */
+
+#ifndef RESOURCED_NET_RESTRICTION_H_
+#define RESOURCED_NET_RESTRICTION_H_
+
+#include <sys/types.h>
+
+#include "data_usage.h"
+#include "transmission.h"
+
+/**
+ * @brief Send network restriction for specific classid
+ * 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
+ * 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
+ * snd_warning_limit - threshold for warning notification on engress bytes
+ * 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 resourced_iface_type iftype,
+                        const int send_limit, const int rcv_limit,
+                        const int snd_warning_threshold,
+                        const int rcv_warning_threshold);
+
+#endif /* RESOURCED_NET_RESTRICTION_H_ */
diff --git a/src/network/include/nfacct-rule.h b/src/network/include/nfacct-rule.h
new file mode 100644 (file)
index 0000000..16b00e1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * resourced
+ *
+ * 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.
+ * 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 nfacct-rule.h
+ *
+ * @desc API for nfacct module
+ *
+ * Copyright (c) 2012-2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef _RESOURCED_NFACCT_RULE_H
+#define _RESOURCED_NFACCT_RULE_H
+
+#include "const.h"
+#include "data_usage.h"
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef enum {
+       NFACCT_COUNTER_UNKNOWN,
+       NFACCT_COUNTER_IN = (1 << 1),
+       NFACCT_COUNTER_OUT = (1 << 2),
+       NFACCT_COUNTER_LAST_ELEM
+} nfacct_rule_direction;
+
+typedef enum {
+       NFACCT_ACTION_UNKNOWN,
+       NFACCT_ACTION_APPEND,
+       NFACCT_ACTION_DELETE,
+       NFACCT_ACTION_INSERT,
+       NFACCT_ACTION_LAST_ELEM,
+} nfacct_rule_action;
+
+typedef enum {
+       NFACCT_JUMP_UNKNOWN,
+       NFACCT_JUMP_ACCEPT,
+       NFACCT_JUMP_REJECT,
+       NFACCT_JUMP_LAST_ELEM,
+} nfacct_rule_jump;
+
+typedef enum {
+       NFACCT_COUNTER,
+       NFACCT_WARN,
+       NFACCT_BLOCK,
+       NFACCT_RULE_LAST_ELEM,
+} nfacct_rule_intend;
+
+struct nfacct_rule {
+       char name[MAX_NAME_LENGTH];
+       char ifname[MAX_NAME_LENGTH];
+
+       pid_t pid;
+       u_int32_t classid;
+       resourced_iface_type iftype;
+       nfacct_rule_direction iotype;
+       nfacct_rule_intend intend;
+       struct counter_arg *carg;
+       resourced_ret_c(*iptables_rule)(struct nfacct_rule *counter);
+       u_int64_t quota;
+};
+
+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_initiate(struct counter_arg *carg);
+
+resourced_ret_c exec_iptables_cmd(const char *cmd_buf, pid_t *pid);
+resourced_ret_c produce_net_rule(struct nfacct_rule *rule,
+                       const int send_limit, const int rcv_limit,
+                       const nfacct_rule_action action,
+                       const nfacct_rule_jump jump,
+                       const nfacct_rule_direction iotype);
+
+#endif /* _RESOURCED_NFACCT_RULE_H */
+
diff --git a/src/network/include/nl-helper.h b/src/network/include/nl-helper.h
new file mode 100644 (file)
index 0000000..0ef417b
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/** @file nl-helper.h
+ *
+ *  @desc Common netlink helper function
+ *
+ *  Created on: Jun 25, 2012
+ */
+
+#ifndef RESOURCED_NL_HELPER_H_
+#define RESOURCED_NL_HELPER_H_
+
+#include "app-stat.h"
+/*#include "nfacct-helper.h"*/
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#include <linux/rtnetlink.h>
+
+#define NLA_BUF_MAX 65560      /*(65 * 1024) - used in tc_common,
+        we'll do the same */
+
+/*TODO: move to common place and rewrite because it's from TC*/
+#define NLMSG_TAIL(nmsg) \
+       ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+
+/*TODO remove unused code */
+typedef struct {
+       struct nlmsghdr n;
+       struct tcmsg t;
+       char buf[NLA_BUF_MAX];
+} rt_param;
+
+void put_attr(rt_param *arg, int type, const void *data, int data_len);
+
+/*
+ * Generic macros for dealing with netlink sockets. Might be duplicated
+ * elsewhere. It is recommended that commercial grade applications use
+ * libnl or libnetlink and use the interfaces provided by the library
+ */
+#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
+
+#define NETLINK_BUF_SIZE 16536
+
+enum nfnl_acct_msg_types {
+       NFNL_MSG_ACCT_NEW,
+       NFNL_MSG_ACCT_GET,
+       NFNL_MSG_ACCT_GET_CTRZERO,
+       NFNL_MSG_ACCT_DEL,
+       NFNL_MSG_ACCT_MAX
+};
+
+enum nfnl_acct_type {
+       NFACCT_UNSPEC,
+       NFACCT_NAME,
+       NFACCT_PKTS,
+       NFACCT_BYTES,
+       NFACCT_USE,
+       NFACCT_FLAGS,
+       NFACCT_QUOTA,
+       NFACCT_FILTER,
+       __NFACCT_MAX
+};
+
+enum nfnl_attr_filter_type {
+       NFACCT_FILTER_ATTR_UNSPEC,
+       NFACCT_FILTER_ATTR_MASK,
+       NFACCT_FILTER_ATTR_VALUE,
+       __NFACCT_FILTER_ATTR_MAX
+};
+
+#define NFACCT_MAX (__NFACCT_MAX - 1)
+
+struct genl {
+        struct nlmsghdr n;
+        struct genlmsghdr g;
+        char buf[NETLINK_BUF_SIZE];
+};
+
+struct netlink_serialization_params {
+       traffic_stat_tree *stat_tree;
+       struct genl *ans;
+       struct counter_arg *carg;
+       int (*eval_attr)(struct rtattr *attr_list[__NFACCT_MAX],
+               void *user_data);
+       int (*post_eval_attr)(void *user_data);
+};
+
+typedef struct {
+       void (*deserialize_answer)(struct netlink_serialization_params *params);
+       void (*finalize)(struct netlink_serialization_params *params);
+       struct netlink_serialization_params params;
+} netlink_serialization_command;
+
+int create_netlink(int protocol, uint32_t groups);
+int read_netlink(int sock, void *buf, size_t len);
+
+void fill_attribute_list(struct rtattr **atb, const int max_len,
+       struct rtattr *rt_na, int rt_len);
+
+#endif /* RESOURCED_NL_HELPER_H_ */
diff --git a/src/network/include/notification.h b/src/network/include/notification.h
new file mode 100644 (file)
index 0000000..fb28122
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 notification.h
+ *
+ * @desc Notification specific functions
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#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);
+
+#endif /* _RESOURCED_DATAUSAGE_NOTIFICATION_H */
+
diff --git a/src/network/include/protocol-info.h b/src/network/include/protocol-info.h
new file mode 100644 (file)
index 0000000..3a8d4ac
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..28a7297
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 restriction-handler.h
+ *
+ * @desc Callback for working reset restrictions
+ */
+
+#ifndef _RESOURCED_RESTRICTION_HANDLER_H_
+#define _RESOURCED_RESTRICTION_HANDLER_H_
+
+#include "iface.h"
+#include "roaming.h"
+
+/**
+ * @brief This function allocates structure
+ * with network up/down handlers.
+ * It's necessary to free memory after usage.
+ */
+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;
+
+#endif /* _RESOURCED_RESTRICTION_HANDLER_H_ */
diff --git a/src/network/include/restriction-helper.h b/src/network/include/restriction-helper.h
new file mode 100644 (file)
index 0000000..0ba219f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 restriction-helper.h
+ * @desc Helper restriction functions
+ */
+
+#ifndef _RESOURCED_RESTRICTION_HELPER_H_
+#define _RESOURCED_RESTRICTION_HELPER_H_
+
+#include "resourced.h"
+#include "transmission.h"
+
+resourced_iface_type get_store_iftype(const u_int32_t app_classid,
+                                     const resourced_iface_type iftype);
+
+resourced_restriction_state convert_to_restriction_state(
+       const enum traffic_restriction_type rst_type);
+
+enum traffic_restriction_type convert_to_restriction_type(
+       const resourced_restriction_state rst_state);
+
+int check_restriction_arguments(const char *appid,
+                               const resourced_net_restrictions *rst,
+                               const enum traffic_restriction_type rst_type);
+
+#endif /* _RESOURCED_RESTRICTION_HELPER_H_ */
diff --git a/src/network/include/roaming.h b/src/network/include/roaming.h
new file mode 100644 (file)
index 0000000..d527fd9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2000 - 2012 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.h
+ *
+ * @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"
+
+/**
+ * @brief Just get roaming state.
+ */
+resourced_roaming_type get_roaming(void);
+
+typedef void(*roaming_cb)(void);
+
+void regist_roaming_cb(roaming_cb cb);
+
+#endif /* _RSML_LIBS_ROAMING_H*/
diff --git a/src/network/include/settings.h b/src/network/include/settings.h
new file mode 100644 (file)
index 0000000..303c831
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 settings.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#ifndef TRESOURCED_LIBS_SETTINGS_H_
+#define TRESOURCED_LIBS_SETTINGS_H_
+
+#include "data_usage.h"
+
+#define RESOURCED_WIFI_STATISTICS_PATH "db/private/resourced/wifi_statistics"
+#define RESOURCED_DATACALL_PATH "db/private/resourced/datacall"
+#define RESOURCED_DATAUSAGE_TIMER_PATH "db/private/resourced/datausage_timer"
+#define RESOURCED_DATACALL_LOGGING_PATH "db/private/resourced/datacall_logging"
+
+int load_options(resourced_options *options);
+
+#endif /*TRESOURCED_LIBS_SETTINGS_H_*/
diff --git a/src/network/include/specific-trace.h b/src/network/include/specific-trace.h
new file mode 100644 (file)
index 0000000..43588b3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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: specific-trace.h
+ *
+ *  @desc Function for print trees for application statistics and for
+ *  traffic statistics.
+ *  @version 1.0
+ *
+ */
+
+
+#ifndef __PERF_CONTROL_SPECIFIC_TRACE_H__
+#define __PERF_CONTROL_SPECIFIC_TRACE_H__
+
+#include "app-stat.h"
+
+#include "macro.h"
+#include "transmission.h"
+
+gboolean print_appstat(gpointer key, gpointer value, void *data);
+
+#endif /*__PERF_CONTROL_SPECIFIC_TRACE_H__*/
diff --git a/src/network/include/storage.h b/src/network/include/storage.h
new file mode 100644 (file)
index 0000000..97fc9b3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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: storage.h
+ *
+ *  @desc Performance management daemon. Helper function
+ *             for working with entity storage.
+ *  @version 1.0
+ *
+ */
+
+
+#ifndef _TRAFFIC_CONTROL_TRAFFIC_STAT_STORAGE_H_
+#define _TRAFFIC_CONTROL_TRAFFIC_STAT_STORAGE_H_
+
+#include <sqlite3.h>
+#include <resourced.h>
+
+#include "app-stat.h"
+#include "iface.h"
+
+/**
+ * @desc Initialize database.
+ *     At present it tweak "pragma synchronous = off"
+ *      and "pragma temp_store = memory"
+ * @param filename - Full path to database
+ */
+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);
+
+/**
+ * @desc Just close sqlite statements.
+ */
+void finalize_storage_stm(void);
+
+/**
+ * @desc Return arguments for network interface processing.
+ *     Argument contains handler function for react on interface changes.
+ *     Changes should be reflect in the database. Whats why it's here.
+ *     We doesn't provide special entity for working with database.
+ */
+iface_callback *create_iface_storage_callback(void);
+
+#endif /*_TRAFFIC_CONTROL_TRAFFIC_STAT_STORAGE_H_*/
diff --git a/src/network/include/tethering-restriction.h b/src/network/include/tethering-restriction.h
new file mode 100644 (file)
index 0000000..047cc05
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 tethering-restriction.h
+ *  @desc Performance management API. Tethering restriction.
+ *  @version 1.0
+ *
+ *  Created on: May 14, 2013
+ */
+
+#ifndef RESOURCED_TETHERING_RESTRICTION_H_
+#define RESOURCED_TETHERING_RESTRICTION_H_
+
+#include "transmission.h"
+
+#define PATH_TO_PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
+
+/*
+ * @desc Apply tethering restriction for tethering pseudo app
+ */
+resourced_ret_c apply_tethering_restriction(
+       const enum traffic_restriction_type type);
+
+#endif /* RESOURCED_TETHERING_RESTRICTION_H_ */
diff --git a/src/network/join.c b/src/network/join.c
new file mode 100644 (file)
index 0000000..83c39da
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 join.c
+ * @desc Implement Performance API. Joining performance control.
+ *    Entity for creation cgroup
+ */
+
+#include <resourced.h>
+
+#include "const.h"
+#include "edbus-handler.h"
+#include "macro.h"
+#include "trace.h"
+
+#ifdef NETWORK_SERVICE_OFF
+API resourced_ret_c join_app_performance(const char *app_id, const pid_t pid)
+{
+       return RESOURCED_ERROR_NONE;
+}
+
+#else
+
+static resourced_ret_c send_join_message(const char *interface,
+       const char *format_str, char *params[])
+{
+       DBusError err;
+       DBusMessage *msg;
+       resourced_ret_c ret_val;
+       int ret, i = 0;
+
+       do {
+               msg = dbus_method_sync(BUS_NAME, RESOURCED_PATH_NETWORK,
+                                      RESOURCED_INTERFACE_NETWORK,
+                                      interface,
+                                      format_str, 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 RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val,
+                                   DBUS_TYPE_INVALID);
+
+       if (ret == FALSE) {
+               _E("no message : [%s:%s]\n", err.name, err.message);
+               ret_val = RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_message_unref(msg);
+       dbus_error_free(&err);
+
+       return ret_val;
+}
+
+API resourced_ret_c join_app_performance(const char *app_id, const pid_t pid)
+{
+       char *params[2];
+
+       if (!app_id)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       serialize_params(params, ARRAY_SIZE(params), app_id, pid);
+
+       return send_join_message(RESOURCED_NETWORK_JOIN_NET_STAT, "sd", params);
+}
+#endif
diff --git a/src/network/ktgrabber-restriction.c b/src/network/ktgrabber-restriction.c
new file mode 100644 (file)
index 0000000..aad8618
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * 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 net-restriction.c
+ *
+ * @desc Kernel communication routins for bloking network traffic based on
+ *     netlink protocol.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <glib.h>
+#include <sys/socket.h>                /*should be before linux/netlink */
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/netlink.h>     /*nlmsghdr */
+#include <linux/pkt_sched.h>
+#include <linux/rtnetlink.h>
+
+#include "resourced.h"
+#include "generic-netlink.h"
+#include "iface.h"
+#include "macro.h"
+#include "netlink-restriction.h"
+#include "nl-helper.h"
+#include "trace.h"
+
+static const char kind_name[] = "htb";
+
+struct rst_context {
+       int sock;
+       int family_id;
+       pid_t pid;
+};
+
+struct nf_arg {
+       u_int32_t classid;
+       enum traffic_restriction_type restriction_type;
+       resourced_iface_type iftype;
+       int error;
+       struct rst_context *context;
+       int send_limit;
+       int rcv_limit;
+       int snd_warning_threshold;
+       int rcv_warning_threshold;
+};
+
+static struct rst_context context;
+
+#if 0
+
+static int send_nl_msg(int sock, pid_t pid, const rt_param *arg)
+{
+       struct sockaddr_nl nladdr = { 0, };
+       struct iovec iov = { 0, };
+       struct msghdr msg = { 0, };
+       int ret = 0;
+
+       if (!arg)
+               return -1;
+
+       iov.iov_base = (void *)(&(arg->n));
+       iov.iov_len = arg->n.nlmsg_len;
+
+       msg.msg_name = &nladdr;
+       msg.msg_namelen = sizeof(nladdr);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+
+       nladdr.nl_family = AF_NETLINK;
+       nladdr.nl_pid = pid;
+       nladdr.nl_groups = 0;
+
+       ret = sendmsg(sock, &msg, 0);
+       if (ret < 0)
+               return -errno;
+       return ret;
+}
+
+static int fill_netlink_argument(u_int32_t classid, u_int32_t *seq,
+                                int command, int flags, rt_param *argument)
+{
+       if (!argument)
+               return -1;
+
+       memset(argument, 0, sizeof(rt_param));
+
+       argument->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
+       argument->n.nlmsg_flags = flags;
+       argument->n.nlmsg_type = command;
+       argument->n.nlmsg_seq = ++(*seq);
+       argument->t.tcm_family = AF_UNSPEC;
+       argument->t.tcm_handle = classid;
+       argument->t.tcm_parent = TC_H_ROOT;
+       argument->t.tcm_ifindex = 2;    /*TODO: use iface by sysctl
+               termination, hardcoded eth0 */
+       return 0;
+}
+
+static void add_htb_param(rt_param *arg)
+{
+       struct tc_htb_glob opt = { 0, };
+       struct rtattr *tail = 0;
+
+       opt.rate2quantum = 1;
+       opt.version = 3;
+
+       put_attr(arg, TCA_KIND, kind_name, sizeof(kind_name) + 1);
+       tail = NLMSG_TAIL(&arg->n);
+       put_attr(arg, TCA_OPTIONS, NULL, 0);
+       put_attr(arg, TCA_HTB_INIT, &opt, NLMSG_ALIGN(sizeof(opt)));
+       /*I don't know why but it present in TC */
+       tail->rta_len = (void *)NLMSG_TAIL(&arg->n) - (void *)tail;
+}
+
+static u_int32_t strict_classid(u_int32_t classid)
+{
+       return classid & 0xFFFF0000;    /* number: in TC termins */
+}
+
+static int add_root_qdisc(int sock, u_int32_t *seq, pid_t pid)
+{
+       rt_param arg;
+       fill_netlink_argument(0, seq, RTM_NEWQDISC,
+                             NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE, &arg);
+       return send_nl_msg(sock, pid, &arg);
+}
+
+/*Create root queue discipline and create base queue discipline*/
+static int add_qdisc(int sock, u_int32_t *seq, pid_t pid, u_int32_t classid)
+{
+       rt_param arg;
+       fill_netlink_argument(classid, seq, RTM_NEWQDISC,
+                             NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE, &arg);
+       add_htb_param(&arg);
+       arg.t.tcm_handle = strict_classid(classid);
+       return send_nl_msg(sock, pid, &arg);
+}
+
+/*At present we support only one type of class*/
+static int add_class(int sock, u_int32_t *seq, pid_t pid, u_int32_t classid,
+                    int rate_limit)
+{
+       rt_param arg;
+       fill_netlink_argument(classid, seq, RTM_NEWTCLASS,
+                             NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE, &arg);
+       return send_nl_msg(sock, pid, &arg);
+}
+
+/*At present we support only one type of filter by cgroup*/
+static int add_filter(int sock, u_int32_t *seq, pid_t pid, u_int32_t classid)
+{
+       rt_param arg;
+       fill_netlink_argument(classid, seq, RTM_NEWTFILTER,
+                             NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE, &arg);
+       return send_nl_msg(sock, pid, &arg);
+}
+#endif
+
+static resourced_ret_c send_nf_restriction(int ifindex, resourced_iface_type iftype,
+       void *data)
+{
+       struct nf_arg *nfarg = data;
+
+       if (!nfarg)
+               return RESOURCED_ERROR_FAIL;
+
+       /* use netfilter (ktgrabber) approach */
+       if (nfarg->iftype == iftype) {
+               _D("Sending restriction to kernel:"\
+               " classid %d, ifindex %d, iftype %d, rest_type %d "\
+               " rcv %d, snd %d",
+               nfarg->classid, ifindex, iftype, nfarg->restriction_type,
+               nfarg->rcv_limit, nfarg->send_limit);
+
+               if (send_restriction(nfarg->context->sock, nfarg->context->pid,
+                       nfarg->context->family_id, nfarg->classid,
+                       ifindex, nfarg->restriction_type,
+                       nfarg->send_limit,
+                       nfarg->rcv_limit,
+                       nfarg->snd_warning_threshold,
+                       nfarg->rcv_warning_threshold) < 0) {
+                       _E("Failed to sent restriction to kernel");
+                       nfarg->error = errno;
+               }
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static gboolean send_each_restriction(gpointer key, gpointer value, gpointer data)
+{
+       return send_nf_restriction((int)key,
+               *(resourced_iface_type *)(value), data) == RESOURCED_ERROR_NONE ?
+               FALSE /* Glib continue iteration */ : TRUE;
+}
+
+static resourced_ret_c init_restriction_context(void)
+{
+       if (context.sock)
+               return 0;
+
+       context.sock = create_netlink(NETLINK_GENERIC, 0);
+
+       if (context.sock < 0) {
+               _D("Failed to create and bind netlink socket.");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       context.family_id = get_family_id(context.sock,
+               context.pid, "TRAF_STAT");
+
+       if (context.family_id < 0) {
+               _D("Failed to get family id.");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       context.pid = getpid(); /* for user/kernel space communication */
+       return RESOURCED_ERROR_NONE;
+}
+
+int send_net_restriction(const enum traffic_restriction_type rst_type,
+                        const u_int32_t classid,
+                        const resourced_iface_type iftype,
+                        const int send_limit, const int rcv_limit,
+                        const int snd_warning_threshold,
+                        const int rcv_warning_threshold)
+{
+       struct nf_arg nfarg;
+
+       /* initialize context variables */
+       if (init_restriction_context() < 0)
+               return RESOURCED_ERROR_FAIL;
+
+       /* emulate old behaviour, no iftype mean block all network interfaces */
+       if (iftype == RESOURCED_IFACE_UNKNOWN ||
+           iftype == RESOURCED_IFACE_ALL) {
+               _D("Sending restriction to kernel: classid %d, ifindex %d "
+                  "iftype %d, restriction_type %d, rcv %d, snd %d\n",
+                  classid, RESOURCED_ALL_IFINDEX, iftype, rst_type,
+                  send_limit, rcv_limit);
+               return send_restriction(context.sock, context.pid,
+                                       context.family_id, classid,
+                                       RESOURCED_ALL_IFINDEX, rst_type,
+                                       send_limit, rcv_limit,
+                                       snd_warning_threshold,
+                                       rcv_warning_threshold);
+       }
+
+       nfarg.context = &context;
+       nfarg.error = 0;
+       nfarg.restriction_type = rst_type;
+       nfarg.iftype = iftype;
+       nfarg.classid = classid;
+       nfarg.send_limit = send_limit;
+       nfarg.rcv_limit = rcv_limit;
+       nfarg.snd_warning_threshold = snd_warning_threshold;
+       nfarg.rcv_warning_threshold = rcv_warning_threshold;
+
+       /* apply a given type of restriction for each network
+          interface of the given network type */
+       init_iftype();
+       for_each_ifindex((ifindex_iterator)send_each_restriction, NULL, &nfarg);
+       return nfarg.error;
+}
diff --git a/src/network/main.c b/src/network/main.c
new file mode 100644 (file)
index 0000000..9b056e4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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 main.c
+ * @desc Implement resource API. Initialization routines.
+ *
+ */
+
+#include <dbus/dbus.h>
+#include <sqlite3.h>
+#include <unistd.h>
+
+#include "const.h"
+#include "cgroup.h"
+#include "datausage-foreach.h"
+#include "datausage-quota.h"
+#include "datausage-reset.h"
+#include "datausage-restriction.h"
+#include "macro.h"
+#include "trace.h"
+
+static void __attribute__ ((constructor)) librsml_initialize(void);
+static void __attribute__ ((destructor)) librsml_deinitialize(void);
+
+static sqlite3 *database;
+
+
+static void librsml_initialize(void)
+{
+       _D("librsml_initialize");
+
+       if (dbus_threads_init_default() != TRUE)
+               _E("Failed to initialize dbus threads support");
+}
+
+#define SQLITE_BUSY_TIMEOUT 500000
+
+static int resourced_db_busy(void UNUSED *user, int attempts)
+{
+       _E("DB locked by another process, attempts number %d", attempts);
+
+       usleep(SQLITE_BUSY_TIMEOUT); /* wait for a half second*/
+       return 1;
+}
+
+API void libresourced_db_initialize_once(void)
+{
+       int res = 0;
+       if (database != NULL)
+               return;
+
+       _D("libresourced_db_initialize_once");
+
+       res = sqlite3_open(DATABASE_FULL_PATH, &database);
+       if (res != SQLITE_OK) {
+               _D("Can't open database %s: %s\n", DATABASE_FULL_PATH,
+                  sqlite3_errmsg(database));
+               sqlite3_close(database);
+               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!");
+       }
+}
+
+static void librsml_deinitialize(void)
+{
+       finalize_datausage_reset();
+       finalize_datausage_foreach();
+       finalize_datausage_restriction();
+       sqlite3_close(database);
+}
+
+API sqlite3 *resourced_get_database(void)
+{
+       libresourced_db_initialize_once();
+       return database;
+}
diff --git a/src/network/net-activity.c b/src/network/net-activity.c
new file mode 100644 (file)
index 0000000..be1cacb
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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: net_activity.h
+ *
+ *  @desc Handler which get data from generic netlink (NET_ACTIVITY) family
+ */
+
+#include "const.h"
+#include "net-cls-cgroup.h"
+#include "generic-netlink.h"
+#include "iface.h"
+#include "macro.h"
+#include "trace.h"
+
+#include <data_usage.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define NET_ACTIVITY_LISTEN_TIMEOUT 10
+
+static pthread_t net_activity_worker;
+
+struct net_activity_context {
+       net_activity_cb cb;
+       uint32_t group_family_id;
+       uint32_t family_id;
+       int sock;
+};
+
+static void set_socket_option(int sock)
+{
+       int ret;
+       int opts = fcntl(sock, F_GETFL);
+
+       ret_msg_if(opts < 0, "fcntl error");
+       opts = (opts | O_NONBLOCK);
+
+       ret = fcntl(sock, F_SETFL, opts);
+       ret_msg_if(ret < 0, "fcntl error");
+}
+
+/**
+ * Convert the netlink multicast group id into a bit map
+ * (e.g. 4 => 16, 5 => 32)
+ */
+static uint32_t convert_mcast_group_id(uint32_t group_id)
+{
+        if (group_id > 31) {
+                _E("Netlink: Use setsockopt for this group: %u\n", group_id);
+                return 0;
+        }
+        return group_id ? (1 << (group_id - 1)) : 0;
+}
+
+static void *net_activity_func(void *user_data)
+{
+       int ret, max_fd;
+       struct net_activity_context *context =
+               (struct net_activity_context *)user_data;
+       struct net_activity_info activity_info;
+       struct timeval timeout = {0};
+
+       fd_set rfd;
+       max_fd = context->sock + 1;
+
+       while (1) {
+               timeout.tv_sec = NET_ACTIVITY_LISTEN_TIMEOUT;
+               FD_ZERO(&rfd);
+               FD_SET(context->sock, &rfd);
+
+               ret = select(max_fd, &rfd, NULL, NULL, &timeout);
+
+               if (ret < 0) {
+                       _E("Failed to select on generic netlink socket");
+                       goto stop_net_activity;
+               }
+
+               if (ret == 0) {
+                       _D("timeout");
+                       continue;
+               }
+
+               ret = recv_net_activity(context->sock, &activity_info,
+                       context->family_id);
+
+               if (ret == RESOURCED_NET_ACTIVITY_STOP)
+                       goto stop_net_activity;
+               else if (ret == RESOURCED_NET_ACTIVITY_CONTINUE)
+                       continue;
+
+               if (context->cb(&activity_info) == RESOURCED_CANCEL)
+                       goto stop_net_activity;
+       }
+
+stop_net_activity:
+       stop_net_activity();
+       close(context->sock);
+       free(context);
+       return NULL;
+
+}
+
+API resourced_ret_c register_net_activity_cb(net_activity_cb activity_cb)
+{
+       int ret;
+       struct net_activity_context *context;
+       pid_t pid;
+
+       ret_value_msg_if(!activity_cb, RESOURCED_ERROR_INVALID_PARAMETER,
+               "Please provide valid callback function!");
+
+       context = (struct net_activity_context *)malloc(
+               sizeof(struct net_activity_context));
+
+       ret_value_if(!context, RESOURCED_ERROR_OUT_OF_MEMORY);
+
+       context->cb = activity_cb;
+       ret = update_classids();
+       if (ret != RESOURCED_ERROR_NONE) {
+               _E("Failed to update appid!");
+               goto free_context;
+       }
+
+       context->sock = create_netlink(NETLINK_GENERIC, 0);
+
+       if (context->sock < 0) {
+               _E("Cant create socket");
+               goto free_context;
+       }
+
+       set_socket_option(context->sock);
+       pid = getpid();
+       /* Initialize family id to communicate with NET_ACTIVITY chanel */
+       context->group_family_id = get_family_group_id(context->sock,
+               pid, "NET_ACTIVITY", "NET_ACT_MCAST", &context->family_id);
+
+       start_net_activity();
+
+       if (context->family_id == 0 || context->group_family_id == 0) {
+               _E("Cant get family id");
+               goto close_socket;
+       }
+
+       /* this one is no more needed */
+       close(context->sock);
+
+       /* New one subscribed to group_family_id */
+       context->sock = create_netlink(NETLINK_GENERIC,
+               convert_mcast_group_id(context->group_family_id));
+
+       if (context->sock < 0) {
+               _E("Failed to create multicast socket!");
+               goto free_context;
+       }
+
+       /* start thread */
+       pthread_create(&net_activity_worker, NULL, net_activity_func,
+               (void *)context);
+
+       return RESOURCED_ERROR_NONE;
+
+close_socket:
+       close(context->sock);
+
+free_context:
+       free(context);
+
+       stop_net_activity();
+       return RESOURCED_ERROR_FAIL;
+}
diff --git a/src/network/net-cls-cgroup.c b/src/network/net-cls-cgroup.c
new file mode 100644 (file)
index 0000000..15cde23
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * 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 classid-helper.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "appid-helper.h"
+#include "net-cls-cgroup.h"
+#include "cgroup.h"
+#include "const.h"
+#include "data_usage.h"
+#include "errors.h"
+#include "file-helper.h"
+#include "macro.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"
+
+struct task_classid {
+       GArray *pids;
+       int pid_count;
+       u_int32_t classid;
+       char cgroup_name[MAX_NAME_LENGTH];      /*in combination it's package name */
+};
+
+typedef GArray task_classid_array;
+static task_classid_array *tasks_classids;
+
+static int read_uint(FILE *handler, u_int32_t *out)
+{
+       return fscanf(handler, "%u", out);
+}
+
+static int read_int(FILE *handler, int *out)
+{
+       return fscanf(handler, "%d", out);
+}
+
+static u_int32_t produce_classid(void)
+{
+       u_int32_t classid = RESOURCED_RESERVED_CLASSID_MAX;
+       int ret = fread_int(CUR_CLASSID_PATH, &classid);
+       if (ret < 0)
+               ETRACE_RET_ERRCODE_MSG(ret, "Can not read current classid");
+       ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
+       if (ret < 0)
+               ETRACE_RET_ERRCODE_MSG(ret, "Can not write classid");
+
+       return classid;
+}
+
+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;
+
+       snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
+       return cgroup_write_node(buf, CLASSID_FILE_NAME, generated_classid);
+}
+
+static u_int32_t get_classid_from_cgroup(const char *cgroup, const char *subdir)
+{
+       char buf[MAX_PATH_LENGTH];
+       u_int32_t classid = RESOURCED_UNKNOWN_CLASSID;
+       snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
+
+       int ret = cgroup_read_node(buf, CLASSID_FILE_NAME, &classid);
+       if (ret < 0)
+               ETRACE_RET_ERRCODE_MSG(ret, "Cant read classid from cgroup %s",
+                       buf);
+       return classid;
+}
+
+static void
+populate_classids_with_pids(const char *dir_name_buf, size_t dir_name_buf_len,
+                 const char *cgroup_name_buf,
+                 task_classid_array **tasks_classids_list)
+{
+       char file_name_buf[MAX_PATH_LENGTH];
+       FILE *handler = 0;
+       struct task_classid tc;
+       memset(&tc, 0, sizeof(struct task_classid));
+       tc.pids = g_array_new(FALSE, FALSE, sizeof(pid_t));
+       pid_t pid_for_read = 0;
+
+       /* first part of path */
+       snprintf(file_name_buf, sizeof(file_name_buf), "%s%s", dir_name_buf,
+               CLASSID_FILE_NAME);
+       handler = fopen(file_name_buf, "r");
+
+       if (!handler) {
+               _E("can't open %s file\n", file_name_buf);
+               return;
+       }
+
+       if (sizeof(tc.cgroup_name) < strlen(cgroup_name_buf))
+               _SE("not enought buffer for %s", cgroup_name_buf);
+       else
+               strcpy(tc.cgroup_name, cgroup_name_buf);
+
+       if (read_uint(handler, &tc.classid) < 0)
+               _E("can't read classid from file %s\n", file_name_buf);
+
+       fclose(handler);
+
+       strncpy(file_name_buf + dir_name_buf_len, TASK_FILE_NAME,
+               dir_name_buf_len + sizeof(TASK_FILE_NAME));
+
+       handler = fopen(file_name_buf, "r");
+
+       if (!handler) {
+               _E("can't open %s file\n", file_name_buf);
+               return;
+       }
+
+       while (read_int(handler, &pid_for_read) >= 0) {
+               tc.pids = g_array_append_val(tc.pids, pid_for_read);
+               ++tc.pid_count;
+       }
+       *tasks_classids_list = g_array_append_val(*tasks_classids_list, tc);
+
+       fclose(handler);
+}
+
+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))
+               return RESOURCED_ALL_APP_CLASSID;
+
+       if (!strcmp(pkg_name, TETHERING_APP_NAME))
+               return RESOURCED_TETHERING_APP_CLASSID;
+
+       /* just read */
+       if (!create)
+               classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
+                       pkg_name);
+
+       if (classid != RESOURCED_UNKNOWN_CLASSID)
+               return classid;
+
+       ret = make_cgroup_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name,
+               &exists);
+       if (ret)
+               goto handle_error;
+
+       if (exists)
+               classid = get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
+                       pkg_name);
+       else
+               ret = place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
+                       (char *)pkg_name, &classid);
+       if (ret)
+               goto handle_error;
+
+       return classid;
+
+ handle_error:
+
+       ETRACE_RET_ERRCODE(ret);
+       return RESOURCED_UNKNOWN_CLASSID;
+}
+
+
+int update_classids(void)
+{
+       DIR *dir;
+       struct dirent *entry;
+
+       char file_name_buf[256];
+       size_t path_to_cgroup_dir_len =
+           sizeof(PATH_TO_NET_CGROUP_DIR), file_name_len;
+
+       sprintf(file_name_buf, "%s/", PATH_TO_NET_CGROUP_DIR);
+
+       if (tasks_classids) {
+               array_foreach(tc, struct task_classid, tasks_classids) {
+                       g_array_free(tc->pids, TRUE);
+               }
+               g_array_free(tasks_classids, TRUE);
+       }
+
+       tasks_classids = g_array_new(FALSE, FALSE, sizeof(struct task_classid));
+
+       dir = opendir(file_name_buf);
+
+       if (!dir)
+               return ERROR_UPDATE_CLASSIDS_LIST;
+
+       while ((entry = readdir(dir)) != 0) {
+               if (entry->d_type != DT_DIR || entry->d_name[0] == '.')
+                       continue;
+
+               file_name_len = strlen(entry->d_name);
+               if (file_name_len + path_to_cgroup_dir_len >
+                   sizeof(file_name_buf)) {
+                       _E("not enought buffer size\n");
+                       continue;
+               }
+
+               strncpy(file_name_buf + path_to_cgroup_dir_len, entry->d_name,
+                       file_name_len + 1);
+
+               populate_classids_with_pids(file_name_buf,
+                                 path_to_cgroup_dir_len + file_name_len,
+                                 entry->d_name, &tasks_classids);
+       }
+       closedir(dir);
+       _D("class id table updated");
+       return 0;
+}
+
+int_array *get_monitored_pids(void)
+{
+       int_array *result = g_array_new(FALSE, FALSE, sizeof(pid_t));
+
+       if (!result) {
+               _D("Out of memory\n");
+               return 0;
+       }
+
+       array_foreach(tc, struct task_classid, tasks_classids) {
+               int i = 0;
+
+               for (; i < tc->pid_count; ++i) {
+                       result = g_array_append_val(result,
+                               g_array_index(tc->pids, int, i));
+               }
+       }
+       return result;
+}
+
+static char *get_app_id_by_classid_local(const u_int32_t classid)
+{
+       if (classid == RESOURCED_TETHERING_APP_CLASSID)
+               return strdup(TETHERING_APP_NAME);
+       array_foreach(tc, struct task_classid, tasks_classids)
+               if (classid == tc->classid)
+                       return strdup(tc->cgroup_name);
+       return 0;
+}
+
+char *get_app_id_by_classid(const u_int32_t classid, const bool update_state)
+{
+       int ret;
+       char *appid = get_app_id_by_classid_local(classid);
+
+       if (appid)
+               return appid;
+
+       _D("can't resolve app id");
+       if (!update_state)
+               return 0;
+
+       ret = update_classids();
+       ret_value_msg_if(ret, 0, "Can't get appid for %d", classid);
+
+       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)
+{
+       int ret = 0;
+       int exists = 0;
+
+       if (pkg_name == NULL) {
+               _E("package name must be not empty");
+               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);
+               ret_value_if(ret < 0, RESOURCED_ERROR_FAIL);
+       }
+
+       return place_pid_to_cgroup(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
+}
+
diff --git a/src/network/network-dummy.c b/src/network/network-dummy.c
new file mode 100644 (file)
index 0000000..e6f0380
--- /dev/null
@@ -0,0 +1,150 @@
+ /*
+ * 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
new file mode 100644 (file)
index 0000000..225e059
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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/network.conf b/src/network/network.conf
new file mode 100644 (file)
index 0000000..d48100f
--- /dev/null
@@ -0,0 +1,6 @@
+[IFACES_TYPE]
+datacall=rmnet
+datacall=pdp
+datacall=seth_w
+
+
diff --git a/src/network/nf-restriction.c b/src/network/nf-restriction.c
new file mode 100644 (file)
index 0000000..e2704e9
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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 nfacct-restriction.c
+ *
+ * @desc Implementation for set up/down restrictions.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "const.h"
+#include "datausage-common.h"
+#include "stdlib.h"
+#include "macro.h"
+#include "module-data.h"
+#include "netlink-restriction.h"
+#include "nfacct-rule.h"
+#include "resourced.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_JUMP_REJECT;
+
+       return produce_net_rule(rule, send_limit, rcv_limit,
+               NFACCT_ACTION_APPEND, jump,
+               NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT);
+}
+
+static resourced_ret_c revert_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_JUMP_REJECT;
+
+       return produce_net_rule(rule, send_limit, rcv_limit,
+               NFACCT_ACTION_DELETE, jump,
+               NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT);
+
+}
+
+static resourced_ret_c exclude_net_restriction(struct nfacct_rule *rule)
+{
+       /* Idea to remove old counter and insert new one at first position
+        * iptables has following architecture: it gets all entries from kernel
+        * modifies this list and returns it back, without iptables it could be
+        * done for one step, but with iptables cmd 2 steps is necessary */
+       rule->intend = NFACCT_COUNTER;
+       resourced_ret_c ret = produce_net_rule(rule, 0, 0,
+               NFACCT_ACTION_DELETE, NFACCT_JUMP_UNKNOWN,
+               NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT);
+
+       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret, "Failed to delete");
+
+       return produce_net_rule(rule, 0, 0,
+               NFACCT_ACTION_INSERT, NFACCT_JUMP_ACCEPT,
+               NFACCT_COUNTER_IN | NFACCT_COUNTER_OUT);
+}
+
+resourced_ret_c send_net_restriction(const enum traffic_restriction_type rst_type,
+                        const u_int32_t classid,
+                        const resourced_iface_type iftype,
+                        const int send_limit, const int rcv_limit,
+                        const int snd_warning_threshold,
+                        const int rcv_warning_threshold)
+{
+       int ret;
+       struct shared_modules_data *m_data = get_shared_modules_data();
+       struct counter_arg *carg;
+       struct nfacct_rule rule = {
+               .name = {0},
+               .ifname = {0},
+               0,
+       };
+
+       ret_value_msg_if(m_data == NULL, RESOURCED_ERROR_FAIL, "Empty shared modules data");
+
+       carg = m_data->carg;
+       ret_value_msg_if(carg == NULL, RESOURCED_ERROR_FAIL, "Empty counter");
+
+
+       rule.classid = classid;
+       rule.iftype = iftype;
+       rule.carg = carg;
+
+       if (rst_type == RST_SET) {
+               if (snd_warning_threshold ||
+                       rcv_warning_threshold) {
+                       rule.intend = NFACCT_WARN;
+                       ret = apply_net_restriction(&rule,
+                               snd_warning_threshold, rcv_warning_threshold);
+                       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                               "Can't apply network restriction");
+               }
+               rule.intend = NFACCT_BLOCK;
+               ret = apply_net_restriction(&rule, send_limit, rcv_limit);
+               ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                               "Can't apply network restriction");
+       } else if (rst_type == RST_UNSET) {
+               rule.intend = NFACCT_WARN;
+               ret = revert_net_restriction(&rule,
+                       snd_warning_threshold, rcv_warning_threshold);
+               ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                       "Can't revert network restriction");
+               rule.intend = NFACCT_BLOCK;
+               return revert_net_restriction(&rule, send_limit,
+                       rcv_limit);
+       } else if (rst_type == RST_EXCLUDE)
+               return exclude_net_restriction(&rule);
+
+       return RESOURCED_ERROR_NONE;
+}
diff --git a/src/network/nfacct-rule.c b/src/network/nfacct-rule.c
new file mode 100644 (file)
index 0000000..c5e2355
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ * 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 nfacct-rule.c
+ *
+ * @desc Datausage module
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "const.h"
+#include "counter.h"
+#include "iface.h"
+#include "macro.h"
+#include "module-data.h"
+#include "nfacct-rule.h"
+#include "nl-helper.h"
+#include "resourced.h"
+#include "trace.h"
+
+#define IPTABLES "/usr/sbin/iptables"
+#define IPTABLES_CHECK "-C"
+#define APPEND "-A"
+#define DELETE "-D"
+#define INSERT "-I"
+
+#define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
+#define REJECT_RULE " -j REJECT"
+#define ACCEPT_RULE " -j ACCEPT"
+
+/* 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
+
+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 */
+};
+
+static void prepare_netlink_msg(struct genl *req, int type, int flag)
+{
+       int seq = time(NULL);
+       memset(req, 0, sizeof(struct genl));
+       req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+       req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type;
+       req->n.nlmsg_flags = NLM_F_REQUEST | flag;
+       req->n.nlmsg_seq = seq;
+}
+
+static void add_value_attr(struct genl *req, const void *data, int len, int type)
+{
+       int payload;
+       /* get tail */
+       struct nlattr *na = (struct nlattr *)(
+                (char *)req + NLMSG_ALIGN(req->n.nlmsg_len));
+
+       na->nla_type = type;
+       payload = len + NLA_HDRLEN;
+       na->nla_len = payload;
+       memcpy(NLA_DATA(na), data, len);
+       req->n.nlmsg_len += NLMSG_ALIGN(payload);
+}
+
+/*
+ * following 2 function should be used in combination.
+ * start_nest_attr returns nlattr structure, which should be completed by
+ * end_nest_attr,
+ * before these invocations any number of netlink arguments could be inserted
+ * */
+static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
+{
+       struct nlattr *start = (struct nlattr *)(
+                (char *)req + NLMSG_ALIGN(req->n.nlmsg_len));
+
+        start->nla_type = NLA_F_NESTED | type;
+        req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
+        return start;
+}
+
+static void end_nest_attr(struct genl *req, struct nlattr *start)
+{
+       start->nla_len = (__u16)(
+                (char *)req + NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
+}
+
+static void add_string_attr(struct genl *req, const char *str, int type)
+{
+       add_value_attr(req, str, strlen(str) + 1, type);
+}
+
+static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
+{
+       add_value_attr(req, &v, sizeof(v), type);
+}
+
+/* macros or templare, due uint64 and uint32 is the same functions */
+static void add_uint32_attr(struct genl *req, const uint32_t v, int type)
+{
+       add_value_attr(req, &v, sizeof(v), type);
+}
+
+static resourced_ret_c send_nfacct_request(int sock, struct genl *req)
+{
+       struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
+       int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
+                     (struct sockaddr *)&nladdr, sizeof(nladdr));
+       ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+                       "Failed to send command to get outgoing traffic");
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static resourced_ret_c nfacct_send_new(struct nfacct_rule *counter)
+{
+       struct genl req;
+
+       prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
+       add_string_attr(&req, counter->name, NFACCT_NAME);
+       _D("counter name %s", counter->name);
+       /* padding */
+       add_uint64_attr(&req, 0, NFACCT_PKTS);
+       add_uint64_attr(&req, 0, NFACCT_BYTES);
+       if (counter->quota) {
+               _D("quota bytes %"PRId64, counter->quota);
+               add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES), NFACCT_FLAGS);
+               add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA);
+       }
+
+       return send_nfacct_request(counter->carg->sock, &req);
+}
+
+static resourced_ret_c nfacct_send_del(struct nfacct_rule *counter)
+{
+       struct genl req;
+
+       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)
+{
+       struct genl req;
+       struct nlattr *na;
+       prepare_netlink_msg(&req, NFNL_MSG_ACCT_GET_CTRZERO,
+               NLM_F_DUMP);
+       /* due we don't get counter with quota any where else,
+       * here we will request just counters by default */
+       na = start_nest_attr(&req, NFACCT_FILTER);
+       add_uint32_attr(&req, NFACCT_F_QUOTAS,
+               NFACCT_FILTER_ATTR_MASK);
+       add_uint32_attr(&req, 0, NFACCT_FILTER_ATTR_VALUE);
+       end_nest_attr(&req, na);
+       return send_nfacct_request(carg->sock, &req);
+}
+
+resourced_ret_c nfacct_send_initiate(struct counter_arg *carg)
+{
+       struct genl req;
+       prepare_netlink_msg(&req, NFNL_MSG_ACCT_GET,
+               NLM_F_DUMP);
+       return send_nfacct_request(carg->sock, &req);
+}
+
+static nfacct_rule_direction convert_to_iotype(int type)
+{
+       return type < NFACCT_COUNTER_LAST_ELEM && type > NFACCT_COUNTER_UNKNOWN ?
+               type : NFACCT_COUNTER_UNKNOWN;
+}
+
+static resourced_iface_type convert_to_iftype(int type)
+{
+       return type < RESOURCED_IFACE_LAST_ELEM && type > RESOURCED_IFACE_UNKNOWN ?
+               type : RESOURCED_IFACE_UNKNOWN;
+}
+
+bool recreate_counter_by_name(char *cnt_name, struct nfacct_rule *cnt)
+{
+       char *iftype_part;
+       char *classid_part;
+       char *io_part;
+       char *ifname_part;
+
+       switch (cnt_name[0]) {
+       case 'c':
+               cnt->intend  = NFACCT_COUNTER;
+               break;
+       case 'w':
+               cnt->intend  = NFACCT_WARN;
+               break;
+       case 'r':
+               cnt->intend  = NFACCT_BLOCK;
+               break;
+       default:
+               return false;
+       }
+
+       io_part = strtok(cnt_name, "_");
+       if (io_part != NULL)
+               cnt->iotype = convert_to_iotype(atoi(io_part + 1));
+       else
+               return false;
+
+       iftype_part = strtok(NULL, "_");
+       if (iftype_part != NULL)
+               cnt->iftype = convert_to_iftype(atoi(iftype_part));
+       else
+               return false;
+
+       classid_part = strtok(NULL, "_");
+       if (classid_part != NULL)
+               cnt->classid = atoi(classid_part);
+       else {
+               cnt->classid = RESOURCED_ALL_APP_CLASSID;
+               return cnt->intend == NFACCT_BLOCK ? true : false;
+       }
+
+       ifname_part = strtok(NULL, "\0");
+       if (ifname_part != NULL)
+               STRING_SAVE_COPY(cnt->ifname, ifname_part);
+       else
+               return false;
+
+       return true;
+}
+
+static void _process_answer(struct netlink_serialization_params *params)
+{
+       struct rtattr *na;
+       struct rtattr *attr_list[__NFACCT_MAX] = {0};
+       struct counter_arg *carg = params->carg;
+       struct genl *ans = params->ans;;
+       struct nlmsghdr *nlhdr = &ans->n;
+       int len = GENLMSG_PAYLOAD(nlhdr);
+       int ans_len = carg->ans_len;
+
+       if (len == 0)
+               return;
+
+       /* parse reply message */
+       na = (struct rtattr *)GENLMSG_DATA(ans);
+
+       while (NLMSG_OK(nlhdr, ans_len )) {
+
+               fill_attribute_list(attr_list, NFACCT_MAX,
+                       na, len);
+               if (!attr_list[NFACCT_NAME] ||
+                       !attr_list[NFACCT_BYTES])
+                       goto next;
+               params->eval_attr(attr_list, carg);
+
+next:
+               nlhdr = NLMSG_NEXT(nlhdr, ans_len);
+               if (ans_len < 0)
+                       break;
+               na = (struct rtattr *)GENLMSG_DATA(nlhdr);
+       }
+
+       if (params->post_eval_attr)
+               params->post_eval_attr(carg);
+}
+
+netlink_serialization_command *netlink_create_command(
+       struct netlink_serialization_params *params)
+{
+       static netlink_serialization_command command = {0,};
+       command.deserialize_answer = _process_answer;
+       command.params = *params;
+       return &command;
+}
+
+static unsigned int get_args_number(const char *cmd_buf)
+{
+       char *str;
+       unsigned int count = 0;
+
+       for (str = (char *)cmd_buf; *str != '\0'; ++str) {
+               if (*str == ' ')
+                       ++count;
+       }
+       return count;
+}
+
+static void wait_for_rule_cmd(struct nfacct_rule *rule, pid_t pid)
+{
+       int status;
+       pid_t ret_pid = waitpid(pid, &status, 0);
+       if (ret_pid < 0)
+               _D("can't wait for a pid %d %d %s", pid, status, strerror(errno));
+}
+
+static char* get_cmd_pos(const char *cmd_buf)
+{
+       char *cmd_pos = strstr(cmd_buf, APPEND);
+       if (!cmd_pos)
+               cmd_pos = strstr(cmd_buf, INSERT);
+
+       return cmd_pos;
+}
+
+static bool is_rule_exists(const char *cmd_buf)
+{
+       size_t buf_len;
+       char *exec_buf;
+       char *cmd_pos = get_cmd_pos(cmd_buf);
+       bool ret = false;
+       if (!cmd_pos)
+               return false;
+
+       buf_len = strlen(cmd_buf) + 1;
+       exec_buf = (char *)malloc(buf_len);
+       if (!exec_buf)
+               return false;
+
+       strncpy(exec_buf, cmd_buf, buf_len);
+       strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
+               sizeof(IPTABLES_CHECK) - 1);
+       _D("check rule %s", exec_buf);
+       ret = system(exec_buf) == 0;
+       free(exec_buf);
+       return ret;
+}
+
+resourced_ret_c exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
+{
+       pid_t pid = fork();
+
+       if (pid == 0) {
+               char *cmd;
+               unsigned int i;
+               const size_t args_number = get_args_number(cmd_buf);
+               char *args[args_number + 2];
+               int ret;
+
+               _D("executing iptables cmd %s in forked process", cmd_buf);
+               ret_value_msg_if(args_number == 0, RESOURCED_ERROR_FAIL, "no arguments");
+
+               if (is_rule_exists(cmd_buf)) {
+                       _D("Rule %s already exists", cmd_buf);
+                       exit(0);
+               }
+               args[0] = "iptables";
+               cmd = strtok((char *)cmd_buf, " ");
+               for (i = 1; i <= args_number; ++i) {
+                       args[i] = strtok(NULL, " ");
+               }
+               args[i] = NULL;
+
+               ret = execv(cmd, args);
+               if (ret)
+                       _E("Can't execute %s: %s",
+                               cmd_buf, strerror(errno));
+               exit(ret);
+       }
+
+       *cmd_pid = pid;
+       return RESOURCED_ERROR_NONE;
+}
+
+static char *choose_iftype_name(struct nfacct_rule *rule)
+{
+       return strlen(rule->ifname) != 0 ? rule->ifname :
+                       get_iftype_name(rule->iftype);
+}
+
+static resourced_ret_c exec_iface_cmd(const char *pattern, const char *cmd,
+               const char *nfacct, const char *jump,
+               char *iftype_name, pid_t *pid)
+{
+       char block_buf[MAX_PATH_LENGTH];
+       int ret;
+
+       ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
+               "Invalid network interface name argument");
+
+       ret = sprintf(block_buf, pattern, IPTABLES, cmd,
+               iftype_name, nfacct, jump);
+       ret_value_msg_if(ret > sizeof(block_buf), RESOURCED_ERROR_NONE,
+               "Not enough buffer");
+       return exec_iptables_cmd(block_buf, pid);
+}
+
+static resourced_ret_c exec_app_cmd(const char *pattern, const char *cmd,
+               const char *nfacct, const char *jump,
+               const u_int32_t classid, char *iftype_name,
+               pid_t *pid)
+{
+       char block_buf[MAX_PATH_LENGTH];
+       int ret;
+       ret_value_msg_if(iftype_name == NULL, RESOURCED_ERROR_FAIL,
+               "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,
+               "Not enough buffer");
+       return exec_iptables_cmd(block_buf, pid);
+}
+
+static char *get_iptables_cmd(const nfacct_rule_action action)
+{
+       if (action == NFACCT_ACTION_APPEND)
+               return APPEND;
+       else if(action == NFACCT_ACTION_DELETE)
+               return DELETE;
+       else if (action == NFACCT_ACTION_INSERT)
+               return INSERT;
+
+       return "";
+}
+
+static char *get_iptables_jump(const nfacct_rule_jump jump)
+{
+       if (jump == NFACCT_JUMP_ACCEPT)
+               return ACCEPT_RULE;
+       else if (jump == NFACCT_JUMP_REJECT)
+               return REJECT_RULE;
+
+       return "";
+}
+
+static resourced_ret_c produce_app_rule(struct nfacct_rule *rule,
+                       const int send_limit, const int rcv_limit,
+                       const nfacct_rule_action action,
+                       const nfacct_rule_jump jump,
+                       const nfacct_rule_direction iotype)
+{
+       char *set_cmd = get_iptables_cmd(action);
+       char *jump_cmd = get_iptables_jump(jump);
+       char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
+               3*MAX_DEC_SIZE(int) + 4];
+       resourced_ret_c ret = RESOURCED_ERROR_NONE;
+       pid_t pid = 0;
+
+       /* income part */
+       if (iotype & NFACCT_COUNTER_IN) {
+               rule->quota = rcv_limit;
+               rule->iotype = NFACCT_COUNTER_IN;
+               generate_counter_name(rule);
+
+               /* to support quated counter we need nfacct,
+                *      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_new(rule);
+                       ret_value_msg_if(ret != RESOURCED_ERROR_NONE, ret,
+                               "can't set nfacct counter");
+               }
+
+               /* 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 = 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,
+                       RESOURCED_ERROR_FAIL, "Can't set conditional block for ingress"
+                               " traffic, for classid %u, cmd %s, j %s",
+                               rule->classid, set_cmd, jump_cmd);
+
+               /* remove in any case */
+               if (action != NFACCT_ACTION_APPEND) {
+                       /* 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");
+               }
+       }
+
+       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_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 = 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");
+               }
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static resourced_ret_c produce_iface_rule(struct nfacct_rule *rule,
+                       const int send_limit, const int rcv_limit,
+                       const nfacct_rule_action action,
+                       const nfacct_rule_jump jump,
+                       const nfacct_rule_direction iotype)
+{
+       char *set_cmd = get_iptables_cmd(action);
+       char *jump_cmd = get_iptables_jump(jump);
+       char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
+               3*MAX_DEC_SIZE(int) + 4];
+       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);
+
+               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,
+                               "Not enought buffer");
+
+               ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd, 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"
+                               " 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");
+               }
+       }
+
+       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,
+                               "Not enough buffer");
+
+               ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, 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");
+               }
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+resourced_ret_c produce_net_rule(struct nfacct_rule *rule,
+                       const int send_limit, const int rcv_limit,
+                       const nfacct_rule_action action,
+                       const nfacct_rule_jump jump,
+                       const nfacct_rule_direction iotype)
+{
+       resourced_ret_c ret = RESOURCED_ERROR_NONE;
+
+       if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN
+               && !send_limit && !rcv_limit)
+               return RESOURCED_ERROR_NONE;
+
+       if (rule->classid != RESOURCED_ALL_APP_CLASSID)
+               ret = produce_app_rule(rule, send_limit,
+                                      rcv_limit, action, jump,
+                                      iotype);
+       else
+               ret = produce_iface_rule(rule, send_limit, rcv_limit,
+                                        action, jump, iotype);
+
+       return ret;
+}
+
+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 (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",
+                       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/nl-helper.c b/src/network/nl-helper.c
new file mode 100644 (file)
index 0000000..4e2e13f
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ *  @file nl-helper.c
+ *  @desc Common netlink helper function
+ *
+ *  Created on: Jun 25, 2012
+ */
+
+#include "nl-helper.h"
+#include "trace.h"
+
+#include <unistd.h>
+#include <linux/rtnetlink.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * create_netlink(): Create netlink socket and returns it.
+ * Returns: Created socket on success and -1 on failure.
+ */
+int create_netlink(int protocol, uint32_t groups)
+{
+       /**
+       * TODO it's one socket, in future make set of sockets
+       * unique for protocol and groups
+       */
+       int sock;
+       sock = socket(PF_NETLINK, SOCK_RAW, protocol);
+       if (sock < 0)
+               return -EINVAL;
+
+       struct sockaddr_nl src_addr = { 0, };
+
+       src_addr.nl_family = AF_NETLINK;
+       src_addr.nl_groups = groups;
+
+       if (bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
+               close(sock);
+               return -1;
+       }
+
+       return sock;
+}
+
+void fill_attribute_list(struct rtattr **atb, const int max_len,
+       struct rtattr *rt_na, int rt_len)
+{
+       int i = 0;
+       while (RTA_OK(rt_na, rt_len)) {
+               if (rt_na->rta_type <= max_len)
+                       atb[rt_na->rta_type] = rt_na;
+
+               rt_na = RTA_NEXT(rt_na, rt_len);
+               ++i;
+               if (i >= max_len)
+                       break;
+       }
+}
+
+/* read netlink message from socket
+ * return opaque pointer to genl structure */
+
+#ifdef CONFIG_DATAUSAGE_NFACCT
+int read_netlink(int sock, void *buf, size_t len)
+{
+       ssize_t ret;
+       struct sockaddr_nl addr;
+       struct iovec iov = {
+               .iov_base       = buf,
+               .iov_len        = len,
+       };
+       struct msghdr msg = {
+               .msg_name       = &addr,
+               .msg_namelen    = sizeof(struct sockaddr_nl),
+               .msg_iov        = &iov,
+               .msg_iovlen     = 1,
+               .msg_control    = NULL,
+               .msg_controllen = 0,
+               .msg_flags      = 0,
+       };
+       ret = recvmsg(sock, &msg, 0);
+       if (ret == -1)
+               return ret;
+
+       if (msg.msg_flags & MSG_TRUNC) {
+               errno = ENOSPC;
+               return -1;
+       }
+
+       if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       return ret;
+}
+#else
+int read_netlink(int sock, void *buf, size_t len)
+{
+       int ans_len;
+       struct genl *ans = buf;
+
+       ans_len = recv(sock, ans, len, MSG_DONTWAIT);
+       if (ans_len < 0)
+               return 0;
+
+       if (ans->n.nlmsg_type == NLMSG_ERROR)
+               return 0;
+
+       if (!NLMSG_OK((&ans->n), ans_len))
+               return 0;
+
+       return ans_len;
+}
+#endif
diff --git a/src/network/notification.c b/src/network/notification.c
new file mode 100644 (file)
index 0000000..f8f96b1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 notification.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 "roaming.h"
+#include "datausage-vconf-common.h"
+
+#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 METHOD_CALL_POPUP "DatausagePopupLaunch"
+
+static int show_restriction_popup(const char *value)
+{
+       char buf[MAX_DEC_SIZE(int)];
+       char str_val[32];
+       char *pa[4];
+       int ret, retval, quota_limit = -1;
+
+       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;
+       }
+
+       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;
+       }
+
+       snprintf(str_val, sizeof(str_val), "%s", value);
+       snprintf(buf, sizeof(buf), "%d", quota_limit);
+
+       pa[0] = NOTI_KEY;
+       pa[1] = str_val;
+       pa[2] = NOTI_KEY_LIMIT;
+       pa[3] = buf;
+
+       ret = dbus_method_async(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_WATCHDOG, SYSTEM_POPUP_IFACE_WATCHDOG, 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)
+{
+       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");
+       show_restriction_popup(NOTI_VALUE_DISABLED);
+}
+
+void send_restriction_warn_notification(const char *appid)
+{
+       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 popup");
+       show_restriction_popup(NOTI_VALUE_WARNING);
+}
+
diff --git a/src/network/options.c b/src/network/options.c
new file mode 100644 (file)
index 0000000..f0927e7
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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 options.c
+ *
+ * @desc Implementation of API for option tweaking:
+ *     wifi - collect information for wifi
+ *     datacall - collect information for packet data
+ *     datausage_time - kernel update period
+ *
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <vconf/vconf.h>
+
+#include "macro.h"
+#include "settings.h"
+#include "trace.h"
+#include "resourced.h"
+#include "const.h"
+
+static int save_options(const resourced_options *options)
+{
+       if (!options) {
+               _E("Please provid valid argument!");
+               return -1;
+       }
+
+       if (vconf_set_bool(RESOURCED_WIFI_STATISTICS_PATH,
+               options->wifi ==  RESOURCED_OPTION_ENABLE ? 1 : 0) != 0) {
+               _D("Can not get WiFi statistics settings");
+               return -1;
+       }
+
+       if (vconf_set_bool(RESOURCED_DATACALL_PATH,
+               options->datacall == RESOURCED_OPTION_ENABLE ? 1 : 0) != 0) {
+               _D("Can not get DataCall settings");
+               return -1;
+       }
+
+       if (vconf_set_int(RESOURCED_DATAUSAGE_TIMER_PATH,
+               options->datausage_timer) != 0) {
+               _D("Can not get DataUsage timer settings");
+               return -1;
+       }
+
+       if (vconf_set_bool(RESOURCED_DATACALL_LOGGING_PATH,
+               options->datacall_logging == RESOURCED_OPTION_ENABLE ? 1 : 0) != 0) {
+               _D("Can not get DataCall logging settings");
+               return -1;
+       }
+       return 0;
+}
+
+API resourced_ret_c set_resourced_options(const resourced_options *options)
+{
+       return save_options(options) ? RESOURCED_ERROR_FAIL : RESOURCED_ERROR_NONE;
+}
+
+API resourced_ret_c get_resourced_options(resourced_options *options)
+{
+       return load_options(options) ? RESOURCED_ERROR_FAIL : RESOURCED_ERROR_NONE;
+}
diff --git a/src/network/protocol-info.c b/src/network/protocol-info.c
new file mode 100644 (file)
index 0000000..e166717
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..766a1a0
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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 reset.c
+ *
+ * @desc Network statistics reset implementation. This function's clearing
+ * datausage database.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <sqlite3.h>
+#include <string.h>
+
+#include "database.h"
+#include "data_usage.h"
+#include "datausage-reset.h"
+#include "macro.h"
+#include "trace.h"
+
+#define RESET_ALL "delete from statistics where time_stamp between ? and ?"
+#define RESET_APP "delete from statistics where binpath=? and " \
+       "time_stamp between ? and ? "
+#define RESET_IFACE "delete from statistics where iftype=? and " \
+       "time_stamp between ? and ?"
+#define RESET_APP_IFACE "delete from statistics where binpath=? and " \
+       "iftype=? and time_stamp between ? and ?"
+
+/* 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];
+
+#define PREPARE(stm, query) do {                               \
+       rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
+       if (rc != SQLITE_OK) {                                  \
+               stm = NULL;                                     \
+               finalize_datausage_reset();                     \
+               _E("Failed to prepare statement for\"%s\"query" \
+                       , query);                               \
+               return rc;                                      \
+       }                                                       \
+} while (0)
+
+static int init_datausage_reset(sqlite3 *db)
+{
+       int rc;
+       static int initialized;
+
+       if (initialized)
+               return SQLITE_OK;
+
+       PREPARE(reset_stms[0], RESET_ALL);
+       PREPARE(reset_stms[1], RESET_APP);
+       PREPARE(reset_stms[2], RESET_IFACE);
+       PREPARE(reset_stms[3], RESET_APP_IFACE);
+
+       initialized = 1;
+       return rc;
+}
+
+#define FINALIZE(stm) do {             \
+       if (stm) {                      \
+               sqlite3_finalize(stm);  \
+               stm = NULL;             \
+       }                               \
+} while (0)
+
+
+void finalize_datausage_reset(void)
+{
+       int i;
+       for (i = 0; i < sizeof(reset_stms) / sizeof(*reset_stms); i++)
+               FINALIZE(reset_stms[i]);
+}
+
+API resourced_ret_c reset_data_usage(const data_usage_reset_rule *rule)
+{
+       sqlite3_stmt *stm;
+       resourced_ret_c result = RESOURCED_ERROR_NONE;
+       int pos = 1;/* running through positions where to
+               bind parameters in the query */
+
+       if (!rule || !rule->interval)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       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;
+       }
+       /* pick a statement depending on parameters.
+               See comment for reset_stms */
+       stm = reset_stms[(rule->app_id ? 1 : 0) |
+               (rule->iftype != RESOURCED_IFACE_LAST_ELEM ? 2 : 0)];
+
+       if (rule->app_id && sqlite3_bind_text(stm, pos++, rule->app_id, -1,
+                       SQLITE_TRANSIENT) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (rule->iftype != RESOURCED_IFACE_LAST_ELEM &&
+               sqlite3_bind_int(stm, pos++, rule->iftype) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_bind_int64(stm, pos++, rule->interval->from) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+       if (sqlite3_bind_int64(stm, pos++, rule->interval->to) != SQLITE_OK) {
+               result = RESOURCED_ERROR_DB_FAILED;
+               goto out;
+       }
+
+       if (sqlite3_step(stm) != SQLITE_DONE) {
+               _D("Failed to drop collected statistics.");
+               result = RESOURCED_ERROR_DB_FAILED;
+       }
+
+out:
+       sqlite3_reset(stm);
+       return result;
+}
+
diff --git a/src/network/restriction-handler.c b/src/network/restriction-handler.c
new file mode 100644 (file)
index 0000000..2d08664
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 restriction-handler.c
+ *
+ * @desc Callback for working reset restrictions
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <data_usage.h>
+#include <stdlib.h>
+#include <net/if.h>
+
+#include "const.h"
+#include "iface.h"
+#include "macro.h"
+#include "net-cls-cgroup.h"
+#include "trace.h"
+#include "restriction-helper.h"
+#include "datausage-restriction.h"
+#include "restriction-handler.h"
+
+struct restriction_context {
+       int ifindex;
+       list_restrictions_info *restrictions;
+};
+
+static gpointer _create_reset_restriction(
+       const resourced_restriction_info *info, const int ifindex)
+{
+       resourced_iface_type iftype;
+       resourced_restriction_info *res_data;
+
+       iftype = get_iftype(ifindex);
+       if (info->iftype != iftype)
+               return NULL;
+
+       res_data = (resourced_restriction_info *)
+               malloc(sizeof(resourced_restriction_info));
+       if (!res_data) {
+               _E("Malloc of resourced_restriction_info failed\n");
+               return NULL;
+       }
+       res_data->app_id = strdup(info->app_id);
+       res_data->iftype = iftype;
+       res_data->rcv_limit = info->rcv_limit;
+       res_data->send_limit = info->send_limit;
+       res_data->rst_state = info->rst_state;
+       res_data->quota_id = info->quota_id;
+       res_data->roaming = info->roaming;
+       return res_data;
+}
+
+static resourced_cb_ret _restriction_iter(
+       const resourced_restriction_info *info, void *user_data)
+{
+       struct restriction_context *context =
+               (struct restriction_context *)(user_data);
+
+       if (!context) {
+               _E("Please provide valid pointer!");
+               return RESOURCED_CONTINUE;
+       }
+
+       _SI("we have restriction for appid %s and check it for ifindex %d\n",
+          info->app_id, context->ifindex);
+       gpointer data = _create_reset_restriction(info, context->ifindex);
+       if (data)
+               context->restrictions = g_list_prepend(context->restrictions,
+                       data);
+       return RESOURCED_CONTINUE;
+}
+
+enum restriction_apply_type
+{
+       KEEP_AS_IS,
+       UNSET,
+};
+
+struct apply_param
+{
+       enum restriction_apply_type apply_type;
+};
+
+static void _reset_restrictions_iter(gpointer data, gpointer user_data)
+{
+       resourced_restriction_info *arg = (resourced_restriction_info *)data;
+       struct apply_param *param = (struct apply_param *)user_data;
+
+       u_int32_t app_classid = RESOURCED_UNKNOWN_CLASSID;
+       resourced_net_restrictions rst = {0};
+       int error_code = RESOURCED_ERROR_NONE;
+       enum traffic_restriction_type rst_type;
+
+       ret_msg_if(!arg || !param, "Please provide valid pointer!");
+
+       rst.iftype = arg->iftype;
+       rst.send_limit = arg->send_limit;
+       rst.rcv_limit = arg->rcv_limit;
+       rst.roaming = arg->roaming;
+
+       if (param->apply_type == KEEP_AS_IS)
+               rst_type = convert_to_restriction_type(arg->rst_state);
+       else if (param->apply_type == UNSET)
+               rst_type = RST_UNSET;
+       else
+               rst_type = RST_UNDEFINDED;
+
+       app_classid = get_classid_by_app_id(arg->app_id, false);
+
+       error_code = process_kernel_restriction(app_classid,
+               &rst, rst_type);
+
+       ret_msg_if(error_code != RESOURCED_ERROR_NONE,
+                        "restriction type %d failed, error %d\n", rst_type,
+                        error_code);
+}
+
+static void _apply_restrictions(const list_restrictions_info *restrictions)
+{
+       struct apply_param param = {.apply_type = KEEP_AS_IS};
+       if (!restrictions) {
+               _D("No restrictions!");
+               return;
+       }
+       g_list_foreach((GList *)restrictions, _reset_restrictions_iter, &param);
+}
+
+static void _reset_restrictions(const list_restrictions_info *restrictions)
+{
+       struct apply_param param = {.apply_type = UNSET};
+       if (!restrictions) {
+               _D("No restrictions!");
+               return;
+       }
+       g_list_foreach((GList *)restrictions, _reset_restrictions_iter, &param);
+}
+
+static void _free_restriction_iter(gpointer data)
+{
+       resourced_restriction_info *arg = (resourced_restriction_info *)data;
+       if (!arg) {
+               _D("No restrictions!");
+               return;
+       }
+       free((char *)arg->app_id);
+       return;
+}
+
+static void _free_reset_restrictions(list_restrictions_info *restrictions)
+{
+       if (!restrictions) {
+               _E("Plese provide valid pointer!");
+               return;
+       }
+       g_list_free_full(restrictions, _free_restriction_iter);
+}
+
+static void process_on_iface_up(const int ifindex)
+{
+       struct restriction_context context = {
+               .restrictions = 0,
+               .ifindex = ifindex,
+       };
+
+       restrictions_foreach(_restriction_iter, &context);
+       if (!context.restrictions) {
+               _D("No restrictions!");
+               return;
+       }
+       _apply_restrictions(context.restrictions);
+       _free_reset_restrictions(context.restrictions);
+}
+
+static void handle_on_iface_up(const int ifindex)
+{
+       process_on_iface_up(ifindex);
+}
+
+static void handle_on_iface_down(const int ifindex)
+{
+       struct restriction_context context = {
+               .restrictions = 0,
+               .ifindex = ifindex,
+       };
+
+       restrictions_foreach(_restriction_iter, &context);
+       if (!context.restrictions) {
+               _D("No restrictions!");
+               return;
+       }
+       _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;
+}
+
+iface_callback *create_restriction_callback(void)
+{
+       iface_callback *ret_arg = (iface_callback *)
+               malloc(sizeof(iface_callback));
+
+       if (!ret_arg) {
+               _E("Malloc of iface_callback failed\n");
+               return NULL;
+       }
+       ret_arg->handle_iface_up = handle_on_iface_up;
+       ret_arg->handle_iface_down = handle_on_iface_down;
+
+       return ret_arg;
+}
+
+void reactivate_restrictions(void)
+{
+       int i;
+       struct if_nameindex *ids = if_nameindex();
+
+       ret_msg_if(ids == NULL,
+                        "Failed to initialize iftype table! errno: %d, %s",
+                        errno, strerror(errno));
+
+       for (i = 0; ids[i].if_index != 0; ++i) {
+               if (!is_address_exists(ids[i].if_name))
+                       continue;
+               process_on_iface_up(ids[i].if_index);
+       }
+
+       if_freenameindex(ids);
+}
diff --git a/src/network/restriction-helper.c b/src/network/restriction-helper.c
new file mode 100644 (file)
index 0000000..609b8c0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 restriction-helper.c
+ * @desc Helper restriction functions
+ */
+
+#include "const.h"
+#include "data_usage.h"
+#include "macro.h"
+#include "trace.h"
+#include "transmission.h"
+
+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 */
+       return (app_classid == RESOURCED_TETHERING_APP_CLASSID) ?
+               RESOURCED_IFACE_ALL : iftype;
+}
+
+resourced_restriction_state convert_to_restriction_state(
+       const enum traffic_restriction_type rst_type)
+{
+       switch (rst_type) {
+       case RST_SET:
+               return RESOURCED_RESTRICTION_ACTIVATED;
+       case RST_UNSET:
+               return RESOURCED_RESTRICTION_REMOVED;
+       case RST_EXCLUDE:
+               return RESOURCED_RESTRICTION_EXCLUDED;
+       default:
+               return RESOURCED_RESTRICTION_UNKNOWN;
+       }
+}
+
+enum traffic_restriction_type convert_to_restriction_type(
+       const resourced_restriction_state rst_state)
+{
+       switch (rst_state) {
+       case RESOURCED_RESTRICTION_ACTIVATED:
+               return RST_SET;
+       case RESOURCED_RESTRICTION_REMOVED:
+               return RST_UNSET;
+       case RESOURCED_RESTRICTION_EXCLUDED:
+               return RST_EXCLUDE;
+       default:
+               return RST_UNDEFINDED;
+       }
+}
+
+int check_restriction_arguments(const char *appid,
+                               const resourced_net_restrictions *rst,
+                               const enum traffic_restriction_type rst_type)
+{
+       ret_value_secure_msg_if(!appid, RESOURCED_ERROR_INVALID_PARAMETER,
+                               "appid is required argument\n");
+       ret_value_msg_if(
+               rst_type <= RST_UNDEFINDED || rst_type >= RST_MAX_VALUE,
+               RESOURCED_ERROR_INVALID_PARAMETER,
+               "Invalid restriction_type %d\n", rst_type);
+       ret_value_msg_if(!rst, RESOURCED_ERROR_INVALID_PARAMETER,
+                        "Restriction should be set\n");
+       ret_value_msg_if(rst->iftype <= RESOURCED_IFACE_UNKNOWN ||
+                        rst->iftype >= RESOURCED_IFACE_LAST_ELEM,
+                        RESOURCED_ERROR_INVALID_PARAMETER,
+                        "Invalid restriction network interface type %d\n",
+                        rst->iftype);
+       if (rst_type == RST_SET) {
+               ret_value_msg_if(rst->send_limit < 0,
+                                RESOURCED_ERROR_INVALID_PARAMETER,
+                                "Invalid send_limit %d\n", rst->send_limit);
+               ret_value_msg_if(rst->rcv_limit < 0,
+                                RESOURCED_ERROR_INVALID_PARAMETER,
+                                "Invalid rcv_limit %d\n", rst->rcv_limit);
+               ret_value_msg_if(rst->snd_warning_limit < 0,
+                                RESOURCED_ERROR_INVALID_PARAMETER,
+                                "Invalid snd_warning_limit %d\n",
+                                rst->snd_warning_limit);
+               ret_value_msg_if(rst->rcv_warning_limit < 0,
+                                RESOURCED_ERROR_INVALID_PARAMETER,
+                                "Invalid rcv_warning_limit %d\n",
+                                rst->rcv_warning_limit);
+       }
+
+       /* check roaming */
+       ret_value_msg_if(rst->roaming >= RESOURCED_ROAMING_LAST_ELEM,
+               RESOURCED_ERROR_INVALID_PARAMETER,
+               "roaming is not valid %d", rst->roaming);
+       return RESOURCED_ERROR_NONE;
+}
diff --git a/src/network/restriction-local.c b/src/network/restriction-local.c
new file mode 100644 (file)
index 0000000..6356300
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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 set-restriction.c
+ * @desc Implementation of the set network restriction body
+ */
+
+#include <sqlite3.h>
+#include <stdbool.h>
+#include <resourced.h>
+
+#include "const.h"
+#include "database.h"
+#include "macro.h"
+#include "module-data.h"
+#include "net-cls-cgroup.h"
+#include "netlink-restriction.h"
+#include "init.h"
+#include "restriction-helper.h"
+#include "datausage-restriction.h"
+#include "roaming.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 (?, ?, ?, ?, ?, ?, ?)"
+
+#define GET_NET_RESTRICTION "SELECT rcv_limit, send_limit, " \
+       " rst_state, quota_id FROM restrictions " \
+       "WHERE binpath = ? AND iftype = ?"
+
+#define RESET_RESTRICTIONS "DELETE FROM restrictions " \
+       "WHERE binpath=? AND iftype=?"
+
+static sqlite3_stmt *update_rst_stm;
+static sqlite3_stmt *reset_rst_stm;
+
+static resourced_ret_c init_reset_rst(void)
+{
+       resourced_ret_c error_code = RESOURCED_ERROR_NONE;
+       if (reset_rst_stm)
+               return error_code;
+
+       DB_ACTION(sqlite3_prepare_v2
+                 (resourced_get_database(), RESET_RESTRICTIONS, -1,
+               &reset_rst_stm, NULL));
+
+       return error_code;
+
+handle_error:
+       _E("Failed to initialize %s", RESET_RESTRICTIONS);
+       return error_code;
+}
+
+static resourced_ret_c reset_restriction_db(const char *app_id,
+                                           const resourced_iface_type iftype)
+{
+       resourced_ret_c error_code = init_reset_rst();
+
+       ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
+
+       DB_ACTION(sqlite3_bind_text(reset_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
+       DB_ACTION(sqlite3_bind_int(reset_rst_stm, 2, iftype));
+
+       if (sqlite3_step(reset_rst_stm) != SQLITE_DONE)
+               error_code = RESOURCED_ERROR_DB_FAILED;
+
+handle_error:
+
+       sqlite3_reset(reset_rst_stm);
+       if (error_code == RESOURCED_ERROR_DB_FAILED)
+               _E("Failed to remove restrictions by network interface %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+
+       return error_code;
+}
+
+static resourced_ret_c init_update_rest_stmt(void)
+{
+       resourced_ret_c error_code = RESOURCED_ERROR_NONE;
+       if (update_rst_stm)
+               return error_code;
+
+       DB_ACTION(sqlite3_prepare_v2
+         (resourced_get_database(), SET_NET_RESTRICTIONS, -1,
+               &update_rst_stm, NULL));
+       return error_code;
+
+handle_error:
+       _E("Failed to initialize %s", SET_NET_RESTRICTIONS);
+       return error_code;
+}
+
+resourced_ret_c update_restriction_db(
+       const char *app_id, const resourced_iface_type iftype,
+       const int rcv_limit, const int snd_limit,
+       const resourced_restriction_state rst_state,
+       const int quota_id,
+       const resourced_roaming_type roaming)
+{
+       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();
+       ret_value_if(error_code != RESOURCED_ERROR_NONE, error_code);
+
+       DB_ACTION(sqlite3_bind_text(update_rst_stm, 1, app_id, -1, SQLITE_TRANSIENT));
+       DB_ACTION(sqlite3_bind_int64(update_rst_stm, 2, rcv_limit));
+       DB_ACTION(sqlite3_bind_int64(update_rst_stm, 3, snd_limit));
+       DB_ACTION(sqlite3_bind_int(update_rst_stm, 4, iftype));
+       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));
+
+       if (sqlite3_step(update_rst_stm) != SQLITE_DONE)
+               error_code = RESOURCED_ERROR_DB_FAILED;
+
+handle_error:
+
+       sqlite3_reset(update_rst_stm);
+       if (error_code == RESOURCED_ERROR_DB_FAILED)
+               _E("Failed to set network restriction: %s\n",
+                       sqlite3_errmsg(resourced_get_database()));
+
+       return error_code;
+}
+
+resourced_ret_c get_restriction_info(const char *app_id,
+                                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;
+
+       ret_value_msg_if(rst == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
+               "Please provide valid restriction argument!");
+
+       ret_value_msg_if(app_id == NULL, RESOURCED_ERROR_INVALID_PARAMETER,
+               "Please provide valid app_id argument!");
+
+       _SD("%s, %d", app_id, iftype);
+
+       DB_ACTION(sqlite3_prepare_v2
+                 (resourced_get_database(), GET_NET_RESTRICTION, -1, &stm, NULL));
+
+       DB_ACTION(sqlite3_bind_text(stm, 1, app_id, -1, SQLITE_TRANSIENT));
+       DB_ACTION(sqlite3_bind_int(stm, 2, iftype));
+
+       do {
+               rc = sqlite3_step(stm);
+               switch (rc) {
+               case SQLITE_ROW:
+                       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);
+
+                       break;
+               case SQLITE_DONE:
+                       break;
+               case SQLITE_ERROR:
+               default:
+                       error_code = RESOURCED_ERROR_DB_FAILED;
+                       goto handle_error;
+               }
+       } while (rc == SQLITE_ROW);
+
+       _D("%d", quota_id);
+
+handle_error:
+
+       if (stm)
+               sqlite3_finalize(stm);
+
+       if (error_code == RESOURCED_ERROR_DB_FAILED)
+               _E("Failed to get network restriction's quota id: %s\n",
+                       sqlite3_errmsg(resourced_get_database()));
+
+       return quota_id;
+}
+
+static bool check_roaming(const resourced_net_restrictions *rst)
+{
+       resourced_roaming_type roaming;
+       ret_value_msg_if(rst == NULL, false,
+               "Invalid net_restriction pointer, please provide valid argument");
+
+       roaming = get_roaming();
+       _D("roaming %d rst->roaming %d", roaming, rst->roaming);
+       if (roaming == RESOURCED_ROAMING_UNKNOWN ||
+               rst->roaming == RESOURCED_ROAMING_UNKNOWN) {
+               return false;
+       }
+       return rst->roaming != roaming;
+}
+
+static void process_net_block_state(const enum
+       traffic_restriction_type rst_type)
+{
+       struct shared_modules_data *m_data = get_shared_modules_data();
+
+       if (m_data)
+               set_daemon_net_block_state(rst_type, m_data->carg);
+       else
+               _E("shared modules data is empty");
+}
+
+resourced_ret_c process_kernel_restriction(
+       const u_int32_t classid,
+       const resourced_net_restrictions *rst,
+       const enum traffic_restriction_type rst_type)
+{
+       int ret = RESOURCED_ERROR_NONE;
+
+       ret_value_secure_msg_if(!classid, RESOURCED_ERROR_INVALID_PARAMETER,
+                        "Can not determine classid for package %u.\n"
+                        "Probably package was not joined to performance "
+                        "monitoring\n", classid);
+
+       if (rst_type == RST_EXCLUDE && check_roaming(rst)) {
+               _D("Restriction not applied: rst->roaming %d", rst->roaming);
+               return RESOURCED_ERROR_NONE;
+       }
+
+       /* 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)
+               ret = apply_tethering_restriction(rst_type);
+       if (classid != RESOURCED_TETHERING_APP_CLASSID &&
+           ret == RESOURCED_ERROR_NONE)
+               ret = send_net_restriction(rst_type, classid,
+                                                 rst->iftype,
+                                                 rst->send_limit,
+                                                 rst->rcv_limit,
+                                                 rst->snd_warning_limit,
+                                                 rst->rcv_warning_limit);
+       ret_value_msg_if(ret < 0, RESOURCED_ERROR_FAIL,
+                        "Restriction, type %d falied, return code %d\n",
+                        rst_type, ret);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+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)
+{
+       u_int32_t app_classid = 0;
+       resourced_iface_type store_iftype;
+       resourced_restriction_state rst_state;
+       int ret = check_restriction_arguments(app_id, rst, rst_type);
+       ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
+                        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.");
+
+       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);
+
+       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);
+}
+
+resourced_ret_c remove_restriction_local(const char *app_id,
+                                        const resourced_iface_type iftype)
+{
+       resourced_net_restrictions rst = { 0 };
+
+       rst.iftype = iftype;
+       return proc_keep_restriction(app_id, NONE_QUOTA_ID, &rst,
+                                        RST_UNSET);
+}
+
+resourced_ret_c exclude_restriction_local(const char *app_id,
+                                         const int quota_id,
+                                         const resourced_iface_type iftype)
+{
+       resourced_net_restrictions rst = { 0 };
+
+       rst.iftype = iftype;
+       return proc_keep_restriction(app_id, quota_id, &rst, RST_EXCLUDE);
+}
diff --git a/src/network/restriction.c b/src/network/restriction.c
new file mode 100644 (file)
index 0000000..ffd0ff3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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 restriction.c
+ * @desc Implementation of the network restriction
+ */
+
+#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"
+#include "edbus-handler.h"
+#include "macro.h"
+#include "netlink-restriction.h"
+#include "restriction-helper.h"
+#include "tethering-restriction.h"
+#include "trace.h"
+
+#define SELECT_RESTRICTIONS "SELECT binpath, rcv_limit, " \
+       "send_limit, iftype, rst_state, quota_id, roaming FROM restrictions"
+
+#define SELECT_RESTRICTION_STATE "SELECT rst_state FROM restrictions " \
+       "WHERE binpath = ? AND iftype = ?"
+
+static sqlite3_stmt *datausage_restriction_select;
+static sqlite3_stmt *restriction_get_state_stmt;
+
+static int init_datausage_restriction(sqlite3 *db)
+{
+       int rc;
+       if (datausage_restriction_select)
+               return SQLITE_OK;
+
+       rc = sqlite3_prepare_v2(db, SELECT_RESTRICTIONS, -1 ,
+                                   &datausage_restriction_select, NULL);
+       if (rc != SQLITE_OK) {
+               _E("can not prepare datausage_restriction_select\n");
+               datausage_restriction_select = NULL;
+               return rc;
+       }
+       return rc;
+}
+
+static void serialize_restriction(const char *appid,
+                                 const enum traffic_restriction_type rst_type,
+                                 const resourced_net_restrictions *rst,
+                                 char *params[])
+{
+       params[0] = (char *)appid;
+       params[1] = (char *)rst_type;
+       params[2] = (char *)rst->rs_type;
+       params[3] = (char *)rst->iftype;
+       params[4] = (char *)rst->send_limit;
+       params[5] = (char *)rst->rcv_limit;
+       params[6] = (char *)rst->snd_warning_limit;
+       params[7] = (char *)rst->rcv_warning_limit;
+       params[8] = (char *)rst->roaming;
+}
+
+static resourced_ret_c process_restriction(
+       const char *app_id, const resourced_net_restrictions *rst,
+       const enum traffic_restriction_type rst_type)
+{
+       DBusError err;
+       DBusMessage *msg;
+       char *params[9];
+       int i = 0, ret;
+       resourced_ret_c ret_val;
+
+       ret = check_restriction_arguments(app_id, rst, rst_type);
+       ret_value_msg_if(ret != RESOURCED_ERROR_NONE,
+                        RESOURCED_ERROR_INVALID_PARAMETER,
+                        "Invalid restriction arguments\n");
+
+       serialize_restriction(app_id, rst_type, rst, params);
+
+       do {
+               msg = dbus_method_sync(BUS_NAME, RESOURCED_PATH_NETWORK,
+                                      RESOURCED_INTERFACE_NETWORK,
+                                      RESOURCED_NETWORK_PROCESS_RESTRICTION,
+                                      "sdddddddd", 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 RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val,
+                                   DBUS_TYPE_INVALID);
+
+       if (ret == FALSE) {
+               _E("no message : [%s:%s]\n", err.name, err.message);
+               ret_val = RESOURCED_ERROR_FAIL;
+       }
+
+       dbus_message_unref(msg);
+       dbus_error_free(&err);
+
+       return ret_val;
+}
+
+API resourced_ret_c restrictions_foreach(
+       resourced_restriction_cb restriction_cb, void *user_data)
+{
+       resourced_restriction_info data;
+       int rc;
+       resourced_ret_c error_code = NETWORK_ERROR_NONE;
+
+       libresourced_db_initialize_once();
+       if (init_datausage_restriction(resourced_get_database()) != SQLITE_OK) {
+               _D("Failed to initialize data usage restriction statement: %s\n",
+                  sqlite3_errmsg(resourced_get_database()));
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+
+       do {
+               rc = sqlite3_step(datausage_restriction_select);
+               switch (rc) {
+               case SQLITE_DONE:
+                       break;
+               case SQLITE_ROW:
+                       data.app_id = (char *)sqlite3_column_text(
+                               datausage_restriction_select, 0);
+                       data.iftype = (resourced_iface_type)sqlite3_column_int(
+                               datausage_restriction_select, 3);
+                       data.rcv_limit = sqlite3_column_int(
+                               datausage_restriction_select, 1);
+                       data.send_limit = sqlite3_column_int(
+                               datausage_restriction_select, 2);
+                       data.rst_state =
+                               (resourced_restriction_state)sqlite3_column_int(
+                                       datausage_restriction_select, 4);
+                       data.quota_id = sqlite3_column_int(
+                               datausage_restriction_select, 5);
+                       data.roaming = sqlite3_column_int(
+                               datausage_restriction_select, 6);
+
+                       if (restriction_cb(&data, user_data) == RESOURCED_CANCEL)
+                               rc = SQLITE_DONE;
+                       break;
+               case SQLITE_ERROR:
+               default:
+                       _E("Failed to enumerate restrictions: %s\n",
+                               sqlite3_errmsg(resourced_get_database()));
+
+                       error_code = RESOURCED_ERROR_DB_FAILED;
+               }
+       } while (rc == SQLITE_ROW);
+
+       sqlite3_reset(datausage_restriction_select);
+       return error_code;
+}
+
+API resourced_ret_c set_net_restriction(const char *app_id,
+                                       const resourced_net_restrictions *rst)
+{
+       return process_restriction(app_id, rst, RST_SET);
+}
+
+API resourced_ret_c remove_restriction(const char *app_id)
+{
+       return remove_restriction_by_iftype(app_id, RESOURCED_IFACE_ALL);
+}
+
+API resourced_ret_c remove_restriction_by_iftype(
+       const char *app_id, const resourced_iface_type iftype)
+{
+       resourced_net_restrictions rst = { 0 };
+
+       rst.iftype = iftype;
+       return process_restriction(app_id, &rst, RST_UNSET);
+}
+
+API resourced_ret_c exclude_restriction(const char *app_id)
+{
+       return exclude_restriction_by_iftype(app_id, RESOURCED_IFACE_ALL);
+}
+
+API resourced_ret_c exclude_restriction_by_iftype(
+       const char *app_id, const resourced_iface_type iftype)
+{
+       resourced_net_restrictions rst = { 0 };
+
+       rst.iftype = iftype;
+       return process_restriction(app_id, &rst, RST_EXCLUDE);
+}
+
+API resourced_ret_c set_net_exclusion(const char *app_id,
+                       const resourced_net_restrictions *rst)
+{
+       return process_restriction(app_id, rst, RST_EXCLUDE);
+}
+
+void finalize_datausage_restriction(void)
+{
+       if (datausage_restriction_select) {
+               sqlite3_finalize(datausage_restriction_select);
+               datausage_restriction_select = NULL;
+       }
+}
+
+static int init_get_rst_statement(sqlite3* db)
+{
+       int rc;
+
+       rc = sqlite3_prepare_v2(db, SELECT_RESTRICTION_STATE, -1 ,
+                                   &restriction_get_state_stmt, NULL);
+       if (rc != SQLITE_OK) {
+               _E("can not prepare restriction_get_state: %d\n", rc);
+               restriction_get_state_stmt = NULL;
+               return NETWORK_ERROR_DB_FAILED;
+       }
+       return rc;
+}
+
+API resourced_ret_c get_restriction_state(const char *pkg_id,
+       resourced_iface_type iftype, resourced_restriction_state *state)
+{
+
+       int error_code = RESOURCED_ERROR_NONE;
+       sqlite3 *db;
+
+       if (state == NULL) {
+               _E("Please provide valid argument!");
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+       }
+
+       db = resourced_get_database();
+
+       if (db == NULL) {
+               _E("Can't get database.");
+               return RESOURCED_ERROR_DB_FAILED;
+       }
+
+       execute_once {
+               error_code = init_get_rst_statement(db);
+               if (error_code != RESOURCED_ERROR_NONE)
+                       return error_code;
+       }
+
+       *state = RESOURCED_RESTRICTION_UNKNOWN;
+       sqlite3_reset(restriction_get_state_stmt);
+       DB_ACTION(sqlite3_bind_text(restriction_get_state_stmt, 1, pkg_id, -1,
+               SQLITE_STATIC));
+       DB_ACTION(sqlite3_bind_int(restriction_get_state_stmt, 2, iftype));
+
+       error_code = sqlite3_step(restriction_get_state_stmt);
+       switch (error_code) {
+       case SQLITE_DONE:
+               break;
+       case SQLITE_ROW:
+               *state = (network_restriction_state)sqlite3_column_int(
+                       restriction_get_state_stmt, 0);
+               break;
+       case SQLITE_ERROR:
+       default:
+               _E("Can't perform sql query: %s \n%s",
+                       SELECT_RESTRICTION_STATE, sqlite3_errmsg(db));
+               error_code = RESOURCED_ERROR_DB_FAILED;
+       }
+
+handle_error:
+
+       sqlite3_reset(restriction_get_state_stmt);
+       return error_code;
+}
+
diff --git a/src/network/roaming.c b/src/network/roaming.c
new file mode 100644 (file)
index 0000000..6152200
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  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/settings.c b/src/network/settings.c
new file mode 100644 (file)
index 0000000..d67e77f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 settings.c
+ *
+ * @desc Entity for load vconf options
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <vconf/vconf.h>
+
+#include "macro.h"
+#include "settings.h"
+#include "trace.h"
+
+API int load_options(resourced_options *options)
+{
+       int val = 0;
+
+       if (!options) {
+               _E("Please provide valid argument!");
+               return -1;
+       }
+       if (vconf_get_bool(RESOURCED_WIFI_STATISTICS_PATH, &val) == 0)
+               options->wifi = val ?
+                       RESOURCED_OPTION_ENABLE : RESOURCED_OPTION_DISABLE;
+       else {
+               _D("Can not get WiFi statistics settings");
+               return -1;
+       }
+
+       if (vconf_get_bool(RESOURCED_DATACALL_PATH, &val) == 0)
+               options->datacall = val ?
+                       RESOURCED_OPTION_ENABLE : RESOURCED_OPTION_DISABLE;
+       else {
+               _D("Can not get DataCall settings");
+               return -1;
+       }
+
+       if (vconf_get_int(RESOURCED_DATAUSAGE_TIMER_PATH, &val) == 0)
+               options->datausage_timer = val;
+       else {
+               _D("Can not get DataUsage timer settings");
+               return -1;
+       }
+
+       if (vconf_get_bool(RESOURCED_DATACALL_LOGGING_PATH, &val) == 0)
+               options->datacall_logging = val ?
+       RESOURCED_OPTION_ENABLE : RESOURCED_OPTION_DISABLE;
+       else {
+               _D("Can not get DataCall logging settings");
+               return -1;
+       }
+       return 0;
+}
diff --git a/src/network/specific-trace.c b/src/network/specific-trace.c
new file mode 100644 (file)
index 0000000..f1d54d1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 specific-trace.c
+ *
+ * @desc functions for tracing complex entities
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "specific-trace.h"
+#include "macro.h"
+#include "trace.h"
+
+gboolean print_appstat(gpointer key, gpointer value,
+       void __attribute__((__unused__)) *data)
+{
+       struct application_stat *appstat = (struct application_stat *)value;
+       struct classid_iftype_key *composite_key =
+               (struct classid_iftype_key *)key;
+
+       if (!appstat || !composite_key) {
+               _E("Please provide valid argument for printing app stat\n");
+               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,
+               appstat->snd_count, (u_int32_t)composite_key->classid,
+               composite_key->iftype, composite_key->ifname,
+               appstat->is_roaming);
+
+       return FALSE;
+}
diff --git a/src/network/storage.c b/src/network/storage.c
new file mode 100644 (file)
index 0000000..f0c67da
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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 storage.c
+ *
+ * @desc Entity for storing applications statistics
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <glib.h>
+#include <inttypes.h>
+#include <sqlite3.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "const.h"
+#include "iface.h"
+#include "database.h"
+#include "datausage-quota-processing.h"
+#include "macro.h"
+#include "protocol-info.h"
+#include "storage.h"
+#include "specific-trace.h"
+#include "trace.h"
+
+static sqlite3_stmt *update_statistics_query;
+static sqlite3_stmt *update_iface_query;
+
+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);
+
+       if (!update_iface_query) {
+               _E("Uninitialized statement");
+               return;
+       }
+       sqlite3_bind_int(update_iface_query, 1, get_iftype(ifindex));
+       sqlite3_bind_int(update_iface_query, 2, state);
+
+       if (sqlite3_step(update_iface_query) != SQLITE_DONE)
+               _E("Failed to record iface state. %s",
+                       sqlite3_errmsg(resourced_get_database()));
+
+       sqlite3_reset(update_iface_query);
+}
+
+static void handle_on_iface_up(const int ifindex)
+{
+       handle_on_iface(ifindex, RESOURCED_OPTION_ENABLE);
+}
+
+static void handle_on_iface_down(const int ifindex)
+{
+       handle_on_iface(ifindex, RESOURCED_OPTION_DISABLE);
+}
+
+static int init_update_statistics_query(sqlite3 *db)
+{
+       int rc;
+
+       if (update_statistics_query)
+               return SQLITE_OK;
+
+       rc = sqlite3_prepare_v2(db,
+                              "insert into statistics "                \
+                              "(binpath, received, sent, time_stamp, " \
+                              "iftype, is_roaming, hw_net_protocol_type, ifname) " \
+                              "values (?, ?, ?, ?, ?, ?, ?, ?)",
+                              read_until_null, &update_statistics_query, NULL);
+
+       if (rc != SQLITE_OK) {
+               _E("Failed to prepare query %s\n", sqlite3_errmsg(db));
+               sqlite3_finalize(update_statistics_query);
+       }
+       return rc;
+}
+
+static int init_update_iface_query(sqlite3 *db)
+{
+       int rc;
+
+       if (update_iface_query)
+               return SQLITE_OK;
+
+       rc =  sqlite3_prepare_v2(db,
+                               "insert into iface_status " \
+               "(update_time, iftype, ifstatus) " \
+               "values (datetime('now'), ?, ?)", read_until_null,
+               &update_iface_query, NULL);
+
+       if (rc != SQLITE_OK) {
+               _E("Failed to prepare query %s\n", sqlite3_errmsg(db));
+               sqlite3_finalize(update_iface_query);
+       }
+       return rc;
+}
+
+static gboolean store_application_stat(gpointer key, gpointer value,
+       gpointer __attribute((__unused__)) userdata)
+{
+       struct application_stat *stat = (struct application_stat *)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);
+
+       if (!update_statistics_query) {
+               _E("Uninitialized statement");
+               return FALSE;
+       }
+
+       if (!stat->rcv_count && !stat->snd_count)
+               return FALSE;
+
+       if (sqlite3_bind_text(update_statistics_query, 1, stat->application_id, read_until_null,
+                       SQLITE_STATIC) != SQLITE_OK) {
+               _SE("Can not bind application_id: %s", stat->application_id);
+               return FALSE;
+       }
+       if (sqlite3_bind_int(update_statistics_query, 2, stat->rcv_count) != SQLITE_OK) {
+               _E("Can not bind rcv_count %d:", stat->rcv_count);
+               return FALSE;
+       }
+       if (sqlite3_bind_int(update_statistics_query, 3, stat->snd_count) != SQLITE_OK) {
+               _E("Can not bind snd_count: %d", stat->snd_count);
+               return FALSE;
+       }
+       if (sqlite3_bind_int64(update_statistics_query, 4, (sqlite3_int64) (*last_touch_time)) !=
+               SQLITE_OK) {
+               _E("Can not bind last_touch_time: %ld", *last_touch_time);
+               return FALSE;
+       }
+       if (sqlite3_bind_int(update_statistics_query, 5, (int)(stat_key->iftype)) != SQLITE_OK) {
+               _E("Can not bind iftype: %d", (int)stat_key->iftype);
+               return FALSE;
+       }
+       if (sqlite3_bind_int(update_statistics_query, 6, (int)(stat->is_roaming)) != SQLITE_OK) {
+               _E("Can not bind is_roaming: %d", (int)(stat->is_roaming));
+               return FALSE;
+       }
+       if (sqlite3_bind_int(update_statistics_query, 7,
+                            (int)hw_net_protocol_type) != SQLITE_OK) {
+               _E("Can not bind protocol_type: %d", (int)hw_net_protocol_type);
+               return FALSE;
+       }
+       if (sqlite3_bind_text(update_statistics_query, 8, stat_key->ifname, read_until_null,
+                       SQLITE_STATIC) != SQLITE_OK) {
+               _SE("Can not bind ifname: %s", stat_key->ifname);
+               return FALSE;
+       }
+
+       /*we want to reuse tree*/
+       stat->rcv_count = 0;
+       stat->snd_count = 0;
+       if (sqlite3_step(update_statistics_query) != SQLITE_DONE)
+               _E("Failed to record appstat. %s", sqlite3_errmsg(resourced_get_database()));
+
+       sqlite3_reset(update_statistics_query);
+       return FALSE;
+}
+
+int store_result(struct application_stat_tree *stats, int flush_period)
+{
+       time_t current_time;
+
+       time(&current_time);
+
+       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;
+}
+
+void finalize_storage_stm(void)
+{
+       sqlite3_finalize(update_statistics_query);
+       sqlite3_finalize(update_iface_query);
+}
+
+iface_callback *create_iface_storage_callback(void)
+{
+       iface_callback *ret_arg =
+               (iface_callback *)malloc(sizeof(iface_callback));
+
+       if (init_update_iface_query(resourced_get_database())
+               != SQLITE_OK) {
+               _E("Initialization database failed\n");
+       }
+       ret_value_msg_if(!ret_arg, NULL, "Malloc of iface_callback failed\n");
+       ret_arg->handle_iface_up = handle_on_iface_up;
+       ret_arg->handle_iface_down = handle_on_iface_down;
+
+       return ret_arg;
+}
diff --git a/src/network/tethering-restriction.c b/src/network/tethering-restriction.c
new file mode 100644 (file)
index 0000000..ff84502
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 tethering-restriction.c
+ *
+ * @desc Implementation of tethering restriction for tethering pseudo app
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include "resourced.h"
+#include "tethering-restriction.h"
+#include "file-helper.h"
+
+resourced_ret_c apply_tethering_restriction(
+       const enum traffic_restriction_type type)
+{
+#ifdef TETHERING_FEATURE
+       static int tethering_exclude;
+       switch (type) {
+       case RST_SET:
+               if (!tethering_exclude)
+                       return fwrite_str(PATH_TO_PROC_IP_FORWARD, "0");
+               return RESOURCED_ERROR_NONE;
+       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
new file mode 100755 (executable)
index 0000000..e141952
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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 update.c
+ *
+ * @desc Implementation of API network statistics update
+ *
+ */
+
+
+#include "resourced.h"
+
+#include "const.h"
+#include "edbus-handler.h"
+#include "macro.h"
+#include "rd-network.h"
+#include "trace.h"
+
+static E_DBus_Signal_Handler *handler;
+static E_DBus_Connection *edbus_conn;
+
+static dbus_bool_t dbus_call_method(const char *dest, const char *path,
+                                    const char *interface, const char *method)
+{
+       DBusConnection *conn;
+       DBusMessage *msg;
+       dbus_bool_t ret;
+
+       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (!conn) {
+               _E("dbus_bus_get failed\n");
+               return FALSE;
+       }
+
+       msg = dbus_message_new_method_call(dest, path, interface, method);
+       if (!msg) {
+               _E("Create dbus message failed\n");
+               return FALSE;
+       }
+
+       ret = dbus_connection_send(conn, msg, NULL);
+       dbus_connection_flush(conn);
+
+       dbus_message_unref(msg);
+       dbus_connection_unref(conn);
+       return ret;
+}
+
+API resourced_ret_c resourced_update_statistics(void)
+{
+       dbus_bool_t ret = dbus_call_method(BUS_NAME,
+                                           RESOURCED_PATH_NETWORK,
+                                           RESOURCED_INTERFACE_NETWORK,
+                                           RESOURCED_NETWORK_UPDATE);
+       if (ret == FALSE) {
+               _D("Error resourced update statistics\n");
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+struct update_context {
+       void *user_data;
+       network_update_cb cb;
+};
+
+static void network_update_dbus_handler(void *user_data, DBusMessage *msg)
+{
+       struct update_context *context;
+       struct network_update_info info;
+
+       ret_msg_if(user_data == NULL,
+               "Not valid user data");
+       context = user_data;
+       ret_msg_if(context->cb == NULL,
+               "Not valid user data");
+
+       if (context->cb(&info, context->user_data) == NETWORK_CANCEL) {
+               network_unregister_update_cb();
+       }
+}
+
+API network_error_e network_register_update_cb(network_update_cb update_cb,
+       void *user_data)
+{
+       static int edbus_init_val;
+       static struct update_context context;
+
+       ret_value_msg_if(update_cb == NULL, NETWORK_ERROR_INVALID_PARAMETER,
+               "Please provide valid callback argument!");
+
+       ret_value_msg_if(handler != NULL, NETWORK_ERROR_INVALID_PARAMETER,
+               "Only one callback is supported!");
+
+       context.user_data = user_data;
+       context.cb = update_cb;
+
+       edbus_init_val = e_dbus_init();
+       ret_value_msg_if(edbus_init_val == 0,
+                NETWORK_ERROR_FAIL, "Fail to initialize dbus!");
+
+       edbus_conn = e_dbus_bus_get(DBUS_BUS_SYSTEM);
+       if (edbus_conn == NULL)
+               goto dbus_release;
+
+       handler = e_dbus_signal_handler_add(edbus_conn, NULL,
+               RESOURCED_PATH_NETWORK,
+               RESOURCED_INTERFACE_NETWORK,
+               RESOURCED_NETWORK_UPDATE_FINISH,
+               network_update_dbus_handler, &context);
+
+       if (handler == NULL)
+               goto dbus_close;
+
+       return NETWORK_ERROR_NONE;
+dbus_close:
+       e_dbus_connection_close(edbus_conn);
+
+dbus_release:
+       e_dbus_shutdown();
+       return NETWORK_ERROR_FAIL;
+}
+
+API void network_unregister_update_cb(void)
+{
+       e_dbus_signal_handler_del(edbus_conn, handler);
+       e_dbus_connection_close(edbus_conn);
+       e_dbus_shutdown();
+
+       handler = NULL;
+       edbus_conn = NULL;
+}
+
similarity index 86%
rename from CMakeLists/powertop-wrapper.txt
rename to src/powertop-wrapper/CMakeLists.txt
index d55a5b8..7f9ae08 100644 (file)
@@ -1,5 +1,5 @@
-
-
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
 
 INCLUDE_DIRECTORIES(${INCLUDE_PUBLIC_DIR} ${POWERTOP-WRAPPER_SOURCE_DIR})
 
@@ -29,6 +29,5 @@ SET_TARGET_PROPERTIES(${POWERTOP-WRAPPER}
      CLEAN_DIRECT_OUTPUT 1
 )
 
-INSTALL(TARGETS ${POWERTOP-WRAPPER} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
-INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/powertop-dapi.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/system)
-
+INSTALL(TARGETS ${POWERTOP-WRAPPER} DESTINATION lib)
+INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/powertop-dapi.h DESTINATION include/system)
similarity index 89%
rename from CMakeLists/proc-stat.txt
rename to src/proc-stat/CMakeLists.txt
index aaed67e..e3ad505 100644 (file)
@@ -1,5 +1,5 @@
-
-
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
 
 INCLUDE_DIRECTORIES(${RESOURCED_INCLUDEDIR}
        ${PROC-STAT_SOURCE_DIR}/include)
@@ -37,8 +37,8 @@ SET_TARGET_PROPERTIES(${PROC-STAT}
 )
 
 
-INSTALL(TARGETS ${PROC-STAT} DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
-INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/proc_stat.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/system)
+INSTALL(TARGETS ${PROC-STAT} DESTINATION lib)
+INSTALL(FILES ${INCLUDE_PUBLIC_DIR}/proc_stat.h DESTINATION include/system)
 
 IF(UNIX)
 
index 3b054ce..d4afec2 100644 (file)
 #define __PROC_MAIN_H__
 
 #include <unistd.h>
+#include <glib.h>
+
+#include "daemon-options.h"
 #include "resourced.h"
+#include "const.h"
 
 #define PROC_BUF_MAX 64
 #define PROC_NAME_MAX 512
 
+typedef GSList *pid_info_list;
+
+enum application_type {
+       RESOURCED_APP_TYPE_UNKNOWN,
+       RESOURCED_APP_TYPE_GUI,
+       RESOURCED_APP_TYPE_SERVICE,
+       RESOURCED_APP_TYPE_GROUP,
+};
+
+struct pid_info_t {
+       pid_t pid;
+       enum application_type type; /* not so fancy */
+};
+
+struct proc_process_info_t {
+       char appid[MAX_PATH_LENGTH];
+       char pkgname[MAX_PATH_LENGTH];
+       pid_info_list pids;
+       int proc_exclude;
+       int runtime_exclude;
+       int memcg_idx;
+       int state;
+       int type;
+};
+
+struct proc_status {
+       pid_t pid;
+       char* appid;
+       struct proc_process_info_t *processinfo;
+};
+
+enum proc_exclude_type {
+       PROC_EXCLUDE,
+       PROC_INCLUDE,
+};
+
+enum {
+       LCD_STATE_ON,
+       LCD_STATE_OFF,
+};
+
+enum proc_prelaunch_flags {
+       PROC_LARGE_HEAP = 0x01u,        /* for mark large heap */
+       PROC_SIGTERM    = 0x02u,        /* for make killer kill victim by SIGTERM */
+};
+
+extern int current_lcd_state;
+
+
+void proc_add_pid_list(struct proc_process_info_t *process_info, int pid, enum application_type type);
 
 int resourced_proc_init(const struct daemon_opts *opts);
 
@@ -41,7 +95,17 @@ int resourced_proc_action(int type, int argnum, char **arg);
 
 int resourced_proc_excluded(const char *app_name);
 
-int resourced_proc_status_change(int type, pid_t pid, char* app_name);
+int resourced_proc_status_change(int type, pid_t pid, char* app_name,  char* pkg_name);
 
-#endif /*__PROC_MAIN_H__ */
+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);
+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);
+int proc_remove_process_list(const pid_t pid);
+void proc_set_apptype(const char *appid, const char *pkgid, int type);
+
+
+#endif /*__PROC_MAIN_H__ */
index 97fe1b7..f8e0080 100644 (file)
 #ifndef __PROC_NOTI_H__
 #define __PROC_NOTI_H__
 
-#define RESMAN_SOCKET_PATH "/tmp/resman"
+#define RESOURCED_SOCKET_PATH "/tmp/resourced"
 #define NOTI_MAXARG    16
-#define NOTI_MAXARGLEN 512
+#define NOTI_MAXARGLEN 256
 
-struct resman_noti { /** cgroup notification type **/
+struct resourced_noti { /** cgroup notification type **/
        int pid;
        int type;
        char *path;
index 15991e0..f118599 100644 (file)
 #define OOMADJ_APP_LIMIT            OOMADJ_INIT
 #define OOMADJ_APP_MAX              (990)
 #define OOMADJ_APP_INCREASE         (30)
+#define OOMADJ_SERVICE_GAP              (10)
+#define OOMADJ_SERVICE_DEFAULT          (OOMADJ_BACKGRD_LOCKED - OOMADJ_SERVICE_GAP)
+#define OOMADJ_SERVICE_FOREGRD         (OOMADJ_FOREGRD_UNLOCKED - OOMADJ_SERVICE_GAP)
+#define OOMADJ_SERVICE_BACKGRD         (OOMADJ_BACKGRD_UNLOCKED - OOMADJ_SERVICE_GAP)
+
+
+enum proc_sweep_type {
+       PROC_SWEEP_EXCLUDE_ACTIVE,
+       PROC_SWEEP_INCLUDE_ACTIVE,
+};
 
 int proc_get_cmdline(pid_t pid, char *cmdline);
-int proc_sweep_memory(int callpid);
+int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid);
 
 int proc_get_oom_score_adj(int pid, int *oom_score_adj);
 int proc_set_oom_score_adj(int pid, int oom_score_adj);
@@ -53,4 +63,6 @@ int proc_set_inactive(int pid, int oom_score_adj);
 
 pid_t find_pid_from_cmdline(char *cmdline);
 
+void proc_set_group(pid_t onwerpid, pid_t childpid);
+
 #endif /*__PROC_PROCESS_H__*/
index 18651b3..01a47b7 100644 (file)
 
 #include <Ecore.h>
 #include <Ecore_File.h>
+#include <pthread.h>
 
+#include "notifier.h"
 #include "proc-process.h"
 #include "proc-main.h"
-
+#include "cgroup.h"
 #include "proc-noti.h"
 #include "trace.h"
-#include "proc-winstate.h"
 #include "proc-handler.h"
 #include "proc-monitor.h"
 #include "module.h"
+#include "macro.h"
+#include "appid-helper.h"
+#include "lowmem-handler.h"
 
+pthread_mutex_t        proc_mutex      = PTHREAD_MUTEX_INITIALIZER;
 static GHashTable *proc_exclude_list;
 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"
+
+enum proc_state {
+       PROC_STATE_DEFAULT,
+       PROC_STATE_FOREGROUND,
+       PROC_STATE_BACKGROUND,
+};
+
+/*
+ * @brief pid_info_list is only for pid_info_t
+ */
+GSList *proc_process_list;
+
+struct pid_info_t *new_pid_info(const pid_t pid, const int type)
+{
+       struct pid_info_t *result = (struct pid_info_t *)malloc(
+                       sizeof(struct pid_info_t));
+       if (!result) {
+               _E("Malloc of new_pid_info failed\n");
+               return NULL;
+       }
+
+       result->pid = pid;
+       result->type = type;
+       return result;
+}
+
+static gint compare_pid(gconstpointer a, gconstpointer b)
+{
+       const struct pid_info_t *pida = (struct pid_info_t *)a;
+       const struct pid_info_t *pidb = (struct pid_info_t *)b;
+       return pida->pid == pidb->pid ? 0 :
+               pida->pid > pidb->pid ? 1 : -1;
+}
+
+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,
+       };
+       GSList *found = NULL;
+
+       ret_value_msg_if(!pids, NULL, "Please provide valid pointer.");
+
+       found = g_slist_find_custom((GSList *)pids,
+               &pid_to_find, compare_pid);
+
+       if (found)
+               return (struct pid_info_t *)(found->data);
+       return NULL;
+}
+
+void proc_add_pid_list(struct proc_process_info_t *process_info, 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,
+       };
+       GSList *found = NULL;
+
+       if (process_info->pids)
+               found = g_slist_find_custom((GSList *)process_info->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));
+       pthread_mutex_unlock(&proc_mutex);
+}
+
+static int equal_process_info(const char *appid_a, const char *appid_b)
+{
+       return !strcmp(appid_a, appid_b);
+}
+
+static resourced_ret_c proc_check_ug(pid_t pid)
+{
+       char buf[PROC_BUF_MAX];
+       char cmdline_buf[PROC_NAME_MAX];
+       FILE *fp;
+
+       snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
+       fp = fopen(buf, "r");
+       if (fp == NULL)
+               return RESOURCED_ERROR_FAIL;
+
+       if (fgets(cmdline_buf, PROC_NAME_MAX-1, fp) == NULL) {
+               fclose(fp);
+               return RESOURCED_ERROR_FAIL;
+       }
+       fclose(fp);
+       if (strstr(cmdline_buf, BASE_UGPATH_PREFIX)) {
+               _D("pid(%d) is ug process. don't freeze this process", pid);
+               return RESOURCED_ERROR_NONFREEZABLE;
+       }
+       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)
+{
+       if (!process_info)
+               return;
+       process_info->memcg_idx = memcg_idx;
+}
+
+struct proc_process_info_t *find_process_info(const char *appid, const pid_t pid, const char *pkgid)
+{
+       GSList *iter = NULL;
+       struct proc_process_info_t *info_t = NULL;
+
+       if (pkgid) {
+               gslist_for_each_item(iter, proc_process_list) {
+                       info_t = (struct proc_process_info_t *)iter->data;
+                       if (equal_process_info(info_t->pkgname, pkgid))
+                               return info_t;
+               }
+               return NULL;
+       }
+
+       if (!pid) {
+               gslist_for_each_item(iter, proc_process_list) {
+                       info_t = (struct proc_process_info_t *)iter->data;
+                       if (equal_process_info(info_t->appid, appid))
+                               return info_t;
+               }
+               return NULL;
+       }
+
+       gslist_for_each_item(iter, proc_process_list) {
+               info_t = (struct proc_process_info_t *)iter->data;
+               if (info_t->pids && find_pid_info(info_t->pids, pid))
+                       return info_t;
+       }
+       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;
+
+       gslist_for_each_item(iter, proc_process_list) {
+               process_info = (struct proc_process_info_t *)iter->data;
+               if (!process_info->pids)
+                       continue;
+
+               found_pid = find_pid_info(process_info->pids, pid);
+               if(!found_pid)
+                       continue;
+
+               if(process_info->runtime_exclude) {
+                       if (type == PROC_EXCLUDE)
+                               process_info->runtime_exclude++;
+                       else
+                               process_info->runtime_exclude--;
+               } else
+                       process_info->runtime_exclude = type;
+
+               _D("found_pid %d, set proc exclude list, type = %d, exclude = %d",
+                           found_pid->pid, type, process_info->runtime_exclude);
+               break;
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+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;
+
+       if (!appid)
+               return NULL;
+
+       process_info = 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 (!process_info) {
+               process_info = malloc(sizeof(struct proc_process_info_t));
+               if (!process_info)
+                       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);
+               if (pkgid)
+                       strncpy(process_info->pkgname, pkgid, MAX_NAME_LENGTH - 1);
+               else
+                       extract_pkgname(process_info->appid, process_info->pkgname,
+                               MAX_NAME_LENGTH);
+               pthread_mutex_lock(&proc_mutex);
+               proc_process_list = g_slist_prepend(proc_process_list,
+                       process_info);
+               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);
+
+       proc_add_pid_list(process_info, pid, type);
+       return process_info;
+}
+
+struct proc_process_info_t * proc_create_process_list(const char *appid, const char *pkgid)
+{
+       struct proc_process_info_t *process_info;
+
+       if (!appid)
+               return NULL;
+
+       process_info = find_process_info(appid, 0, pkgid);
+       /* do not add if it already in list */
+       if (process_info)
+               return process_info;
+
+       if (!process_info) {
+               process_info = malloc(sizeof(struct proc_process_info_t));
+               if (!process_info)
+                       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);
+               if (pkgid)
+                       strncpy(process_info->pkgname, pkgid, MAX_NAME_LENGTH - 1);
+               else
+                       extract_pkgname(process_info->appid, process_info->pkgname,
+                               MAX_NAME_LENGTH);
+               pthread_mutex_lock(&proc_mutex);
+               proc_process_list = g_slist_prepend(proc_process_list,
+                       process_info);
+               pthread_mutex_unlock(&proc_mutex);
+               process_info->state = PROC_STATE_DEFAULT;
+       }
+       return process_info;
+}
+
+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;
+
+       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)
+                       continue;
+
+               found_pid = find_pid_info(process_info->pids, pid);
+               if(!found_pid)
+                       continue;
+
+               _D("found_pid %d", found_pid->pid);
+               /* 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);
+               }
+               break;
+       }
+       pthread_mutex_unlock(&proc_mutex);
+       return 0;
+}
 
 static void proc_free_exclude_key(gpointer data)
 {
@@ -63,16 +398,13 @@ int resourced_proc_excluded(const char *app_name)
        return ret ? RESOURCED_ERROR_NONMONITOR : RESOURCED_ERROR_NONE;
 }
 
-#if 0
 static void _prepare_appid(char *appid, const int length)
 {
        if (!appid || length - 1 <= 0)
                return;
        appid[length - 1] = '\0'; /*remove ending new line*/
 }
-#endif
 
-#if 0
 static void fill_exclude_list_by_path(const char *exclude_file_name,
        GHashTable *list)
 {
@@ -114,13 +446,11 @@ static void fill_exclude_list_by_path(const char *exclude_file_name,
 
        fclose(exclude_file);
 }
-#endif
 
 static void _fill_exclude_list(GHashTable *list)
 {
-#if 0
-       fill_exclude_list_by_path( , list);
-#endif
+       fill_exclude_list_by_path(EXCLUDE_LIST_FULL_PATH, list);
+       fill_exclude_list_by_path(EXCLUDE_LIST_OPT_FULL_PATH, list);
 }
 
 static void _exclude_list_change_cb(void *data, Ecore_File_Monitor *em,
@@ -171,8 +501,6 @@ int resourced_proc_init(const struct daemon_opts *opts)
 
        proc_notifd = proc_noti_init( );
 
-       proc_win_status_init();
-
        ret = proc_monitor_init();
        if (ret)
                _E("proc_monitor_init failed : %d", ret);
@@ -187,18 +515,41 @@ int resourced_proc_exit(const struct daemon_opts *opts)
                close(proc_notifd);
        g_hash_table_destroy(proc_exclude_list);
        ecore_file_monitor_del(exclude_list_monitor);
+       g_slist_free_full(proc_process_list, free);
        return RESOURCED_ERROR_NONE;
 }
 
-int resourced_proc_status_change(int type, pid_t pid, char* app_name)
+void proc_set_apptype(const char *appid, const char *pkgid, int type)
+{
+       struct proc_process_info_t *process_info =
+               proc_create_process_list(appid, pkgid);
+       if (process_info)
+               process_info->type = type;
+}
+
+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;;
 
        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;
+       }
+
+       if (!pid) {
+               _E("invalid pid : %d of %s", pid, app_name ? app_name : "noprocess");
                return RESOURCED_ERROR_FAIL;
        }
 
+       proc_data.pid = pid;
+       proc_data.appid = app_name;
+       proc_data.processinfo = NULL;
        switch (type) {
        case PROC_CGROUP_SET_FOREGRD:
                _SD("set foreground : %d", pid);
@@ -206,10 +557,9 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name)
                dbus_proc_handler(PREDEF_FOREGRD, pidbuf);
                ret = proc_set_foregrd(pid, oom_score_adj);
                if (ret != 0)
-                       _E("Failed to handle proc foreground action!");
-               if ( oom_score_adj < OOMADJ_BACKGRD_UNLOCKED)
-                       break;
-
+                       return RESOURCED_ERROR_NO_DATA;
+               proc_update_process_state(pid, PROC_STATE_FOREGROUND);
+               resourced_notify(RESOURCED_NOTIFIER_APP_FOREGRD, &proc_data);
                break;
        case PROC_CGROUP_SET_LAUNCH_REQUEST:
                proc_set_oom_score_adj(pid, OOMADJ_INIT);
@@ -218,33 +568,54 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name)
                        return RESOURCED_ERROR_NO_DATA;
                }
                _SD("launch request %s, %d", app_name, pid);
-
+               if (pkg_name)
+                       _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);
+               resourced_notify(RESOURCED_NOTIFIER_APP_LAUNCH, &proc_data);
+               _E("available memory = %u", get_available());
                break;
        case PROC_CGROUP_SET_SERVICE_REQUEST:
-               proc_set_oom_score_adj(pid, OOMADJ_INIT);
                if (!app_name) {
                        _E("need application name!pid = %d", pid);
                        return RESOURCED_ERROR_NO_DATA;
                }
                _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);
+               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)
+               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);
+
                break;
        case PROC_CGROUP_SET_TERMINATE_REQUEST:
+               resourced_notify(RESOURCED_NOTIFIER_APP_TERMINATE, &proc_data);
+               proc_remove_process_list(pid);
                break;
        case PROC_CGROUP_SET_ACTIVE:
                ret = proc_set_active(pid, oom_score_adj);
+               if (ret != RESOURCED_ERROR_OK)
+                       break;
+               resourced_notify(RESOURCED_NOTIFIER_APP_ACTIVE, &proc_data);
+               proc_set_runtime_exclude_list(pid, PROC_EXCLUDE);
                break;
        case PROC_CGROUP_SET_BACKGRD:
                snprintf(pidbuf, sizeof(pidbuf), "%d", pid);
@@ -252,17 +623,21 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name)
                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);
+               if (ret != RESOURCED_ERROR_OK)
+                       break;
+               resourced_notify(RESOURCED_NOTIFIER_APP_INACTIVE, &proc_data);
                break;
        case PROC_CGROUP_GET_MEMSWEEP:
-               ret = proc_sweep_memory(pid);
+               ret = proc_sweep_memory(PROC_SWEEP_EXCLUDE_ACTIVE, pid);
                break;
        case PROC_CGROUP_SET_NOTI_REQUEST:
                break;
        case PROC_CGROUP_SET_PROC_EXCLUDE_REQUEST:
+               proc_set_runtime_exclude_list(pid, PROC_EXCLUDE);
                break;
        default:
                ret = RESOURCED_ERROR_INVALID_PARAMETER;
@@ -272,8 +647,8 @@ int resourced_proc_status_change(int type, pid_t pid, char* app_name)
 
 int resourced_proc_action(int type, int argnum, char **arg)
 {
-       int pid;
-       char *pidbuf = NULL, *cgroup_name = NULL;
+       pid_t pid;
+       char *pidbuf = NULL, *cgroup_name = NULL, *pkg_name = NULL;
        if (argnum < 1) {
                _E("Unsupported number of arguments!");
                return RESOURCED_ERROR_INVALID_PARAMETER;
@@ -286,11 +661,12 @@ int resourced_proc_action(int type, int argnum, char **arg)
        }
 
        /* Getting appid */
-       if (argnum > 1) {
+       if (argnum > 1)
                /* It's possible to get appid from arg */
                cgroup_name = arg[1];
-       }
+       if (argnum == 3)
+               pkg_name = arg[2];
        _SD("appid %s, pid %d, type %d \n", cgroup_name, pid, type);
-       return resourced_proc_status_change(type, pid, cgroup_name);
+       return resourced_proc_status_change(type, pid, cgroup_name, pkg_name);
 }
 
index 799054b..5ae3008 100644 (file)
 #include "trace.h"
 #include "edbus-handler.h"
 #include "proc-process.h"
+#include "lowmem-handler.h"
+#include "notifier.h"
+
+#include <journal/system.h>
 
 #define WATCHDOG_LAUNCHING_PARAM "WatchdogPopupLaunch"
 #define WATCHDOG_KEY1                  "_SYSPOPUP_CONTENT_"
 #define SIGNAL_PROC_WATCHDOG_RESULT    "WatchdogResult"
 #define SIGNAL_PROC_ACTIVE             "Active"
 #define SIGNAL_PROC_EXCLUDE            "ProcExclude"
+#define SIGNAL_PROC_PRELAUNCH          "ProcPrelaunch"
 #define SIGNAL_PROC_STATUS             "ProcStatus"
+#define SIGNAL_PROC_SWEEP              "ProcSweep"
+#define SIGNAL_PROC_WATCHDOG           "ProcWatchdog"
+#define SIGNAL_PROC_GROUP              "ProcGroup"
+#define TIZEN_DEBUG_MODE_FILE   "/opt/etc/.debugmode"
+
+
+#define INIT_PID       1
+#define INIT_PROC_VAL  -1
 
 static int proc_watchdog_state;
 static int proc_dbus_proc_state;
+int current_lcd_state;
+
+static Ecore_Timer *watchdog_check_timer = NULL;
+#define WATCHDOG_TIMER_INTERVAL                90
 
 /*
  * Callback function executed by edbus 'Signal' method call. Extracts
@@ -80,6 +97,14 @@ enum proc_status_type { /** cgroup command type **/
        PROC_STATUS_BACKGRD,
 };
 
+static int check_debugenable(void)
+{
+       if (access(TIZEN_DEBUG_MODE_FILE, F_OK) == 0)
+               return 1;
+       else
+               return 0;
+}
+
 void proc_set_watchdog_state(int state)
 {
        proc_watchdog_state = state;
@@ -97,7 +122,6 @@ static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
        char *str;
        pid_t pid;
 
-       _D("call dbus_proc_active_signal_handler");
        ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_ACTIVE);
        if (ret == 0) {
                _D("there is no active signal");
@@ -117,7 +141,7 @@ static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
                type = PROC_CGROUP_SET_INACTIVE;
        else
                return;
-       resourced_proc_status_change(type, pid, NULL);
+       resourced_proc_status_change(type, pid, NULL, NULL);
 }
 
 int proc_get_dbus_proc_state(void)
@@ -171,8 +195,8 @@ static void proc_dbus_proc_signal_handler(void *data, DBusMessage *msg)
        default:
                return;
        }
-       _D("call dbus_proc_active_signal_handler : pid = %d, type = %d", pid, convert);
-       resourced_proc_status_change(convert, pid, NULL);
+       _D("call proc_dbus_proc_signal_handler : pid = %d, type = %d", pid, convert);
+       resourced_proc_status_change(convert, pid, NULL, NULL);
 }
 
 static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
@@ -182,7 +206,6 @@ static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
        char *str;
        pid_t pid;
 
-       _D("call dbus_proc_active_signal_handler");
        ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_EXCLUDE);
        if (ret == 0) {
                _D("there is no active signal");
@@ -196,7 +219,71 @@ static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
                return;
        }
 
-       return;
+       _D("call proc_dbus_exclude_signal_handler : pid = %d, str = %s", pid, str);
+       if (!strcmp(str, "exclude"))
+               proc_set_runtime_exclude_list(pid, PROC_EXCLUDE);
+       else if (!strcmp(str, "include"))
+               proc_set_runtime_exclude_list(pid, PROC_INCLUDE);
+       else
+               return;
+}
+
+static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int ret;
+       char *appid;
+       char *pkgid;
+       int flags;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
+               SIGNAL_PROC_PRELAUNCH);
+       if (ret == 0) {
+               _D("there is no prelaunch signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_message_get_args(msg, &err,
+               DBUS_TYPE_STRING, &appid,
+               DBUS_TYPE_STRING, &pkgid,
+               DBUS_TYPE_INT32, &flags, DBUS_TYPE_INVALID) == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       _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);
+               lowmem_dynamic_process_killer(DYNAMIC_KILL_LARGEHEAP);
+       }
+}
+
+static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int ret;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
+               SIGNAL_PROC_SWEEP);
+
+       if (ret == 0) {
+               _D("there is no sweep signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+       proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
+}
+
+static Eina_Bool check_watchdog_cb(void *data)
+{
+       ecore_timer_del(watchdog_check_timer);
+       watchdog_check_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
 }
 
 static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
@@ -217,8 +304,13 @@ static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
        }
 
        if (type == 1) {
-               if (proc_watchdog.signum == SIGTERM || proc_watchdog.signum == SIGKILL)
+               if (proc_watchdog.signum == SIGTERM || proc_watchdog.signum == SIGKILL) {
                        kill(proc_watchdog.pid, SIGABRT);
+                       if (watchdog_check_timer == NULL) {
+                               watchdog_check_timer =
+                                       ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
+                       }
+               }
                else
                        _E("ERROR: Unsupported signal type!");
        }
@@ -268,6 +360,95 @@ static int proc_dbus_show_popup(const char *value)
        return ret_val;
 }
 
+static void proc_dbus_watchdog_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int pid, command, ret;
+       char appname[PROC_NAME_MAX];
+
+       if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG) == 0) {
+               _D("there is no watchdog result signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
+               &command, DBUS_TYPE_INVALID);
+
+       if (ret == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       ret = proc_get_cmdline(pid, appname);
+       if (ret != RESOURCED_ERROR_NONE) {
+               _E("ERROR : invalid pid(%d)", pid);
+               return;
+       }
+
+       if (proc_watchdog.pid != INIT_PROC_VAL) {
+               _E("pid %d(%s) has already received watchdog siganl", pid, appname);
+               return;
+       }
+       ret = resourced_proc_excluded(appname);
+       if (ret == RESOURCED_ERROR_NONMONITOR)
+               return;
+
+       if (current_lcd_state == LCD_STATE_OFF) {
+               _E("Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
+               return;
+       }
+
+       _E("Receive watchdog signal to pid: %d(%s)\n", pid, appname);
+       journal_system_anr(appname);
+       if (watchdog_check_timer) {
+               _E("current killing watchdog process. so skipped kill %d(%s)\n", pid, appname);
+               return;
+       }
+
+       if (check_debugenable()) {
+               _E("just kill watchdog process when debug enabled pid: %d(%s)\n", pid, appname);
+               kill(pid, SIGABRT);
+               if (watchdog_check_timer == NULL) {
+                       watchdog_check_timer =
+                               ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
+       }
+       }
+       else {
+               ret = proc_dbus_show_popup(appname);
+               if (ret < 0)
+                       _E("ERROR : request_to_launch_by_dbus()failed : %d", ret);
+               else {
+                       proc_watchdog.pid = pid;
+                       proc_watchdog.signum = command;
+               }
+       }
+}
+
+static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int pid, childpid, ret;
+
+       if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_GROUP) == 0) {
+               _D("there is no watchdog result signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
+               &childpid, DBUS_TYPE_INVALID);
+
+       if (ret == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       proc_set_group(pid, childpid);
+}
+
 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
 {
        DBusMessage *reply;
@@ -304,26 +485,80 @@ static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
        return reply;
 }
 
+static void proc_dbus_lcd_on(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON) == 0) {
+               _D("there is no lcd on signal");
+               return;
+       }
+       dbus_error_free(&err);
+       current_lcd_state = LCD_STATE_ON;
+       resourced_notify(RESOURCED_NOTIFIER_LCD_ON, NULL);
+       /* nothing */
+}
+
+static void proc_dbus_lcd_off(void *data, DBusMessage *msg)
+{
+       DBusError err;
+
+       dbus_error_init(&err);
+       if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF) == 0) {
+               _D("there is no lcd on signal");
+               return;
+       }
+
+       dbus_error_free(&err);
+       current_lcd_state = LCD_STATE_OFF;
+       resourced_notify(RESOURCED_NOTIFIER_LCD_OFF, NULL);
+}
+
+
 static resourced_ret_c proc_dbus_init(void)
 {
-       int ret;
        register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_WATCHDOG_RESULT,
                    proc_dbus_watchdog_result);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_ACTIVE,
                    proc_dbus_active_signal_handler);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_EXCLUDE,
                    proc_dbus_exclude_signal_handler);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_PRELAUNCH,
+                   proc_dbus_prelaunch_signal_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_STATUS,
                    proc_dbus_proc_signal_handler);
 
-       _D("register_edbus_signal_handler: %d\n", ret);
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_SWEEP,
+                   proc_dbus_sweep_signal_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_WATCHDOG,
+                   proc_dbus_watchdog_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_WATCHDOG,
+                   proc_dbus_grouping_handler);
+
+       register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
+                   DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on);
+
+       register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
+                   DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off);
+
+       /* start watchdog check timer for preveting ANR during booting */
+       watchdog_check_timer =
+               ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
 
        return edbus_add_methods(RESOURCED_PATH_PROCESS, edbus_methods,
                          ARRAY_SIZE(edbus_methods));
index eba2aef..bbfa6b0 100644 (file)
@@ -124,7 +124,7 @@ static inline char *recv_str(int fd)
  * of string type
  * @return 0 on success errno constants in error case
 */
-static int read_message(int fd, struct resman_noti *msg)
+static int read_message(int fd, struct resourced_noti *msg)
 {
        int i;
 
@@ -153,7 +153,7 @@ static inline void internal_free(char *str)
                free(str);
 }
 
-static inline void free_message(struct resman_noti *msg)
+static inline void free_message(struct resourced_noti *msg)
 {
        int i;
 
@@ -164,7 +164,7 @@ static inline void free_message(struct resman_noti *msg)
        free(msg);
 }
 
-static int process_message(struct resman_noti *msg)
+static int process_message(struct resourced_noti *msg)
 {
        _D("process message caller pid %d\n", msg->pid);
        return resourced_proc_action(msg->type, msg->argc, msg->argv);
@@ -187,7 +187,7 @@ static void safe_write_int(int fd, int type, int *value)
 static Eina_Bool proc_noti_cb(void *data, Ecore_Fd_Handler *fd_handler)
 {
        int fd;
-       struct resman_noti *msg;
+       struct resourced_noti *msg;
        int ret = -1;
        struct sockaddr_un client_address;
        int client_sockfd;
@@ -201,7 +201,7 @@ static Eina_Bool proc_noti_cb(void *data, Ecore_Fd_Handler *fd_handler)
 
        fd = ecore_main_fd_handler_fd_get(fd_handler);
 
-       msg = malloc(sizeof(struct resman_noti));
+       msg = malloc(sizeof(struct resourced_noti));
        if (msg == NULL) {
                _E("proc_noti_cb : Not enough memory");
                return ECORE_CALLBACK_RENEW;
@@ -252,8 +252,8 @@ static int proc_noti_socket_init(void)
        int fd;
        struct sockaddr_un serveraddr;
 
-       if (access(RESMAN_SOCKET_PATH, F_OK) == 0)
-               unlink(RESMAN_SOCKET_PATH);
+       if (access(RESOURCED_SOCKET_PATH, F_OK) == 0)
+               unlink(RESOURCED_SOCKET_PATH);
 
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0) {
@@ -279,7 +279,7 @@ static int proc_noti_socket_init(void)
 
        bzero(&serveraddr, sizeof(struct sockaddr_un));
        serveraddr.sun_family = AF_UNIX;
-       strncpy(serveraddr.sun_path, RESMAN_SOCKET_PATH,
+       strncpy(serveraddr.sun_path, RESOURCED_SOCKET_PATH,
                sizeof(serveraddr.sun_path));
 
        if (bind(fd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr)) <
@@ -289,7 +289,7 @@ static int proc_noti_socket_init(void)
                return -1;
        }
 
-       if (chmod(RESMAN_SOCKET_PATH, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
+       if (chmod(RESOURCED_SOCKET_PATH, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
                _E("failed to change the socket permission");
 
        if (listen(fd, 5) < 0) {
index 30744c7..a299bcf 100644 (file)
 #include "resourced.h"
 #include "trace.h"
 #include "proc-main.h"
-
+#include "cgroup.h"
 #include "proc-process.h"
 #include "lowmem-common.h"
+#include "logging-common.h"
 #include "macro.h"
-#include "cpu-common.h"
+#include "swap-common.h"
 #include "proc-noti.h"
-#include "proc-winstate.h"
+#include "notifier.h"
 
 #define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
 #define PROC_SWEEP_TIMER       3
 static GHashTable *proc_sweep_list;
 static Ecore_Timer *proc_sweep_timer = NULL;
 
-static int proc_backgrd_manage(int currentpid)
+enum proc_background_type {
+       PROC_BACKGROUND_INACTIVE,
+       PROC_BACKGROUND_ACTIVE,
+};
+
+static int proc_backgrd_manage(int currentpid, int active)
 {
        int pid = -1, pgid, ret;
+       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;
        static int checkprevpid = 0;
-       unsigned long lowmem_args[2] = {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 (ret || checkprevpid == currentpid) {
+               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;
                }
@@ -67,6 +85,7 @@ static int proc_backgrd_manage(int currentpid)
                return RESOURCED_ERROR_FAIL;
        }
        while ((dentry = readdir(dp)) != NULL) {
+
                if (!isdigit(dentry->d_name[0]))
                        continue;
 
@@ -75,24 +94,91 @@ static int proc_backgrd_manage(int currentpid)
                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) {
-                       _D("found owner pid = %d, pgid = %d", pid, pgid);
-                       lowmem_args[0] = (unsigned long)pid;
-                       lowmem_args[1] = (unsigned long)OOMADJ_BACKGRD_UNLOCKED;
-                       lowmem_control(LOWMEM_MOVE_CGROUP, lowmem_args);
+                       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;
+               }
+
+               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;
+               }
+
+               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);
+       }
+
+       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);
        }
        checkprevpid = currentpid;
        closedir(dp);
+
+       logging_control(LOGGING_UPDATE_PROC_INFO, NULL);
+
        return RESOURCED_ERROR_NONE;
 }
 
-static void proc_foregrd_manage(int pid)
+static int proc_foregrd_manage(int pid, int oom_score_adj)
 {
-       unsigned long lowmem_args[2] = {0, };
-       lowmem_args[0] = (unsigned long)pid;
-       lowmem_control(LOWMEM_MANAGE_FOREGROUND, lowmem_args);
+       int ret = 0;
+       GSList *iter;
+       struct proc_process_info_t *process_info =
+               find_process_info(NULL, pid, NULL);
+
+       if (!process_info) {
+               ret = proc_set_oom_score_adj(pid, oom_score_adj);
+               return ret;
+       }
+
+       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);
+       }
+       return ret;
 }
 
 void proc_kill_victiom(gpointer key, gpointer value, gpointer user_data)
@@ -105,7 +191,7 @@ void proc_kill_victiom(gpointer key, gpointer value, gpointer user_data)
        snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
        fp = fopen(buf, "r+");
        if (fp == NULL) {
-               _D("sweep proc_kill_victiom : background process %d already terminated", pid);
+               _D("sweep proc_kill_victim : background process %d already terminated", pid);
                return;
        }
        if (fgets(buf, sizeof(buf), fp) == NULL) {
@@ -129,9 +215,10 @@ static Eina_Bool proc_check_sweep_cb(void *data)
        return ECORE_CALLBACK_CANCEL;
 }
 
-int proc_sweep_memory(int callpid)
+int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
 {
-       int pid = -1, count=0, ret;
+       pid_t pid = -1;
+       int count=0, ret;
        DIR *dp;
        struct dirent *dentry;
        FILE *fp;
@@ -140,6 +227,7 @@ int proc_sweep_memory(int callpid)
        char appname[PROC_NAME_MAX];
 
        int cur_oom = -1;
+       int select_sweep_limit;
        dp = opendir("/proc");
        if (!dp) {
                _E("BACKGRD MANAGE : fail to open /proc");
@@ -151,6 +239,11 @@ int proc_sweep_memory(int callpid)
                g_hash_table_destroy(proc_sweep_list);
        proc_sweep_list = g_hash_table_new(g_int_hash, g_int_equal);
 
+       if (type == PROC_SWEEP_EXCLUDE_ACTIVE)
+               select_sweep_limit = OOMADJ_BACKGRD_UNLOCKED;
+       else
+               select_sweep_limit = OOMADJ_BACKGRD_LOCKED;
+
        while ((dentry = readdir(dp)) != NULL) {
                if (!isdigit(dentry->d_name[0]))
                        continue;
@@ -168,12 +261,13 @@ int proc_sweep_memory(int callpid)
                        continue;
                }
                cur_oom = atoi(buf);
-               if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
+               if (cur_oom >= select_sweep_limit) {
                        ret = proc_get_cmdline(pid, appname);
                        if (ret != 0) {
                                fclose(fp);
                                continue;
                        }
+                       proc_remove_process_list(pid);
                        piddata = g_new(gint, 1);
                        *piddata = pid;
                        g_hash_table_insert(proc_sweep_list, piddata, NULL);
@@ -222,7 +316,6 @@ int proc_get_cmdline(pid_t pid, char *cmdline)
        return RESOURCED_ERROR_NONE;
 }
 
-
 int proc_get_oom_score_adj(int pid, int *oom_score_adj)
 {
        char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
@@ -233,8 +326,11 @@ int proc_get_oom_score_adj(int pid, int *oom_score_adj)
 
        snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
        fp = fopen(buf, "r");
-       if (fp == NULL)
+
+       if (fp == NULL) {
+               _E("fopen %s failed", buf);
                return RESOURCED_ERROR_FAIL;
+       }
        if (fgets(buf, sizeof(buf), fp) == NULL) {
                fclose(fp);
                return RESOURCED_ERROR_FAIL;
@@ -269,7 +365,7 @@ int proc_set_oom_score_adj(int pid, int oom_score_adj)
        return 0;
 }
 
-int proc_set_foregrd(int pid, int oom_score_adj)
+int proc_set_foregrd(pid_t pid, int oom_score_adj)
 {
        int ret = 0;
 
@@ -280,16 +376,11 @@ int proc_set_foregrd(int pid, int oom_score_adj)
                ret = 0;
                break;
        case OOMADJ_BACKGRD_LOCKED:
-               proc_foregrd_manage(pid);
-               ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
+               ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_LOCKED);
                break;
        case OOMADJ_BACKGRD_UNLOCKED:
-               cpu_control(CPU_SET_FOREGROUND, pid);
-               proc_foregrd_manage(pid);
-               ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
-               break;
        case OOMADJ_INIT:
-               ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
+               ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED);
                break;
        default:
                if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
@@ -311,15 +402,14 @@ int proc_set_backgrd(int pid, int oom_score_adj)
        case OOMADJ_BACKGRD_LOCKED:
        case OOMADJ_BACKGRD_UNLOCKED:
        case OOMADJ_SU:
-               _D("don't change oom value pid = (%d) oom_score_adj (%d)!", pid, 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);
                break;
        case OOMADJ_FOREGRD_UNLOCKED:
-               proc_backgrd_manage(pid);
-               cpu_control(CPU_SET_BACKGROUND, pid);
+               proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE);
                ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
                break;
        case OOMADJ_INIT:
@@ -344,6 +434,7 @@ 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;
@@ -353,15 +444,15 @@ int proc_set_active(int pid, int oom_score_adj)
        case OOMADJ_BACKGRD_UNLOCKED:
                ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
                break;
-       case OOMADJ_INIT:
-               ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
+       case OOMADJ_SERVICE_DEFAULT:
+       case OOMADJ_SERVICE_BACKGRD:
+               ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_FOREGRD);
                break;
        default:
-               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
+               if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED)
                        ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
-               } else {
+               else
                        ret = -1;
-               }
                break;
        }
        return ret;
@@ -370,11 +461,12 @@ 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;
        switch (oom_score_adj) {
        case OOMADJ_FOREGRD_UNLOCKED:
        case OOMADJ_BACKGRD_UNLOCKED:
        case OOMADJ_SU:
+       case OOMADJ_INIT:
                /* don't change oom value pid */
                ret = -1;
                break;
@@ -382,10 +474,12 @@ 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:
-               ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
+               processinfo = find_process_info(NULL, pid, NULL);
+               if (processinfo)
+                       ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
                break;
-       case OOMADJ_INIT:
-               ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
+       case OOMADJ_SERVICE_FOREGRD:
+               ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_DEFAULT);
                break;
        default:
                if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
@@ -399,6 +493,22 @@ int proc_set_inactive(int pid, int oom_score_adj)
        return ret;
 }
 
+void proc_set_group(pid_t onwerpid, pid_t childpid)
+{
+       int oom_score_adj = 0;
+       struct proc_process_info_t *process_info =
+               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);
+               proc_set_oom_score_adj(childpid, oom_score_adj);
+       }
+}
+
 pid_t find_pid_from_cmdline(char *cmdline)
 {
        pid_t pid = -1, foundpid = -1;
@@ -421,7 +531,7 @@ pid_t find_pid_from_cmdline(char *cmdline)
                        continue;
                ret = proc_get_cmdline(pid, appname);
                if (ret == RESOURCED_ERROR_NONE) {
-                       if (strstr(cmdline, appname)) {
+                       if (!strcmp(cmdline, appname)) {
                                foundpid = pid;
                                break;
                        }
index ea67fbb..bb9cbbb 100644 (file)
@@ -57,8 +57,6 @@ do { \
 } while (0)
 #endif
 
-#define NOTI_MAXARGLEN 512
-
 API bool proc_stat_get_cpu_time_by_pid(pid_t pid, unsigned long *utime,
                                       unsigned long *stime)
 {
@@ -210,9 +208,9 @@ API bool proc_stat_get_free_mem_size(unsigned int *free_mem)
        char *buffer = NULL;
        const int buffer_size = 4096;
        int len = 0;
-       static const char *const items[] = { "MemFree:", "Buffers:", "Cached:", "Shmem:" };
+       static const char *const items[] = { "MemFree:", "Buffers:", "Cached:", "SwapCached:", "Shmem:" };
        static const int items_len[] = { sizeof("MemFree:"), sizeof("Buffers:"), sizeof("Cached:"),
-                                                         sizeof("Shmem:") };
+                                                         sizeof("SwapCached:"), sizeof("Shmem:") };
        static const int items_cnt = ARRAY_SIZE(items);
        unsigned int mem_size[items_cnt];
        int num_found;
@@ -240,8 +238,8 @@ API bool proc_stat_get_free_mem_size(unsigned int *free_mem)
        if (num_found < items_cnt)
                return false;
 
-       /* free_mem = "MemFree" + "Buffers" + "Cached" - "Shmem" */
-       *free_mem = (mem_size[0] + mem_size[1] + mem_size[2] - mem_size[4]) / 1024;
+       /* free_mem = "MemFree" + "Buffers" + "Cached" + "SwapCache" - "Shmem" */
+       *free_mem = (mem_size[0] + mem_size[1] + mem_size[2] + mem_size[3] - mem_size[4]) / 1024;
 
        return true;
 }
@@ -762,7 +760,7 @@ static inline int send_str(int fd, char *str)
        return ret;
 }
 
-static int send_socket(struct resman_noti *msg, bool sync)
+static int send_socket(struct resourced_noti *msg, bool sync)
 {
        int client_len;
        int client_sockfd;
@@ -779,7 +777,7 @@ static int send_socket(struct resman_noti *msg, bool sync)
 
        bzero(&clientaddr, sizeof(clientaddr));
        clientaddr.sun_family = AF_UNIX;
-       strncpy(clientaddr.sun_path, RESMAN_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
+       strncpy(clientaddr.sun_path, RESOURCED_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
        client_len = sizeof(clientaddr);
 
        if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
@@ -811,7 +809,7 @@ static int send_socket(struct resman_noti *msg, bool sync)
 
 static resourced_ret_c proc_cgroup_send_status(const int type, int num, ...)
 {
-       struct resman_noti *msg;
+       struct resourced_noti *msg;
        resourced_ret_c ret = RESOURCED_ERROR_NONE;
        va_list argptr;
 
@@ -819,7 +817,7 @@ static resourced_ret_c proc_cgroup_send_status(const int type, int num, ...)
        char *args = NULL;
        bool sync = SYNC_OPERATION(type);
 
-       msg = malloc(sizeof(struct resman_noti));
+       msg = malloc(sizeof(struct resourced_noti));
 
        if (msg == NULL)
                return RESOURCED_ERROR_OUT_OF_MEMORY;
@@ -890,3 +888,14 @@ API resourced_ret_c proc_cgroup_sweep_memory(void)
        return proc_cgroup_send_status(PROC_CGROUP_GET_MEMSWEEP, 1, buf);
 }
 
+API resourced_ret_c proc_cgroup_launch(int type, pid_t pid, char* app_id, char* pkg_id)
+{
+       char pid_buf[MAX_DEC_SIZE(int)];
+       char appid_buf[NOTI_MAXARGLEN];
+       char pkgid_buf[NOTI_MAXARGLEN];
+       snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
+       snprintf(appid_buf, sizeof(appid_buf)-1, "%s", app_id);
+       snprintf(pkgid_buf, sizeof(pkgid_buf)-1, "%s", pkg_id);
+       return proc_cgroup_send_status(type, 3, pid_buf, appid_buf, pkgid_buf);
+}
+
diff --git a/src/proc-stat/proc-winstate.c b/src/proc-stat/proc-winstate.c
deleted file mode 100644 (file)
index 9d43c44..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <resourced.h>
-
-#include "proc-winstate.h"
-#include "proc-main.h"
-#include "proc-process.h"
-#include "proc-monitor.h"
-#include "trace.h"
-
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-#include <Ecore.h>
-#include <Ecore_X.h>
-#include <Ecore_Evas.h>
-#include <Ecore_Input_Evas.h>
-
-static Atom a_pid;
-
-typedef struct  _ProcWininfo {
-    struct _ProcWininfo *prev, *next;
-    int idx;
-    long pid;
-    Window winid;
-} ProcWininfo, *ProcWininfoPtr;
-
-static pid_t __get_win_pid(Display *d, Window win)
-{
-       int r;
-       pid_t pid;
-
-       Atom a_type;
-       int format;
-       unsigned long nitems;
-       unsigned long bytes_after;
-       unsigned char *prop_ret;
-       XWindowAttributes attr;
-
-       //_retv_if(d == NULL || !a_pid, -1);
-
-       if (!XGetWindowAttributes(d, win, &attr))
-               return -1;
-
-       if (attr.override_redirect || attr.class == InputOnly)
-               return -1;
-
-       prop_ret = NULL;
-       r = XGetWindowProperty(d, win, a_pid, 0, 1, False, XA_CARDINAL,
-                              &a_type, &format, &nitems, &bytes_after,
-                              &prop_ret);
-       if (r != Success || prop_ret == NULL)
-               return -1;
-
-       if (a_type == XA_CARDINAL && format == 32)
-               pid = *(unsigned long *)prop_ret;
-       else
-               pid = -1;
-
-       XFree(prop_ret);
-
-       return pid;
-}
-
-static Window get_window(Display *d, Window win)
-{
-       Atom type_ret = 0;
-       int ret, size_ret = 0;
-       unsigned long num_ret = 0, bytes = 0;
-       unsigned char *prop_ret = NULL;
-       unsigned int xid;
-       Atom prop_user_created_win;
-
-       prop_user_created_win = XInternAtom(d, "_E_USER_CREATED_WINDOW", False);
-
-       ret = XGetWindowProperty(d, win, prop_user_created_win, 0L, 1L,
-            False, XA_WINDOW, &type_ret, &size_ret,
-            &num_ret, &bytes, &prop_ret);
-
-       if( ret != Success )
-       {
-               if( prop_ret ) XFree( (void*)prop_ret );
-               return win;
-       }
-       else if( !prop_ret )
-       {
-               return win;
-       }
-
-       memcpy( &xid, prop_ret, sizeof(unsigned int) );
-       XFree( (void *)prop_ret );
-
-       return xid;
-}
-
-static void free_procwininfo(ProcWininfoPtr procwininfo)
-{
-       ProcWininfoPtr w;
-/* TODO : free winname and appname map_state*/
-       w = procwininfo;
-       if (!w)
-               return;
-       while(1)
-       {
-               if(w && w->next)
-                       w = w->next;
-               else
-                       break;
-       }
-       while(1)
-       {
-               if(w && w->prev)
-               {
-                       w = w->prev;
-                       free(w->next);
-               }
-               else
-               {
-                       if(w)
-                               free(w);
-                       break;
-               }
-       }
-}
-
-
-static int __find_win(Display *d, pid_t pid)
-{
-       int r, i, found = 0;
-       pid_t p;
-       unsigned int n;
-       int win_index = 0, winid = 0;
-       Window root, parent, *child;
-       Window win;
-       ProcWininfoPtr prev_wininfo = NULL;
-       ProcWininfoPtr cur_wininfo = NULL;
-       ProcWininfoPtr origin_wininfo = NULL;
-       XWindowAttributes attr;
-
-       win = XDefaultRootWindow(d);
-
-       r = XQueryTree(d, win, &root, &parent, &child, &n);
-       if (!r) {
-               _E("Can't query window tree.");
-               return 0;
-       }
-
-       for (i = (int)n - 1; i >= 0; i--)
-       {
-               if (!XGetWindowAttributes(d, child[i], &attr)) {
-                       _E("Can't get window tree.");
-                       continue;
-               }
-               if (attr.map_state) {
-                       cur_wininfo = (ProcWininfoPtr) malloc(sizeof(ProcWininfo));
-                       cur_wininfo->idx = win_index++;
-                       cur_wininfo->next = NULL;
-                       cur_wininfo->prev = NULL;
-                       cur_wininfo->winid = child[i];
-               } else
-                       continue;
-               if(prev_wininfo)
-               {
-                       prev_wininfo->next = cur_wininfo;
-                       cur_wininfo->prev = prev_wininfo;
-               } else
-                       origin_wininfo = cur_wininfo;
-
-               /* set the pre_wininfo is the cur_wininfo now */
-               prev_wininfo = cur_wininfo;
-       }
-       if (!origin_wininfo) {
-               _E("Can't get valid window info");
-               if (child)
-                       XFree((char *)child);
-               return 0;
-       }
-
-       ProcWininfoPtr w = origin_wininfo;
-       for(i = 0; i < win_index; i++)
-       {
-               winid = get_window(d, w->winid);
-               w->winid = winid;
-               p = __get_win_pid(d, w->winid);
-               if (p == pid) {
-                       found++;
-                       _D("__find_win : pid %d, win %x", pid, w->winid);
-                       ecore_x_window_client_sniff(w->winid);
-               }
-               w = w->next;
-       }
-       if (child)
-               XFree((char *)child);
-       free_procwininfo(origin_wininfo);
-       return 0;
-}
-
-static inline int _get_pid(Ecore_X_Window win)
-{
-       int pid;
-       Ecore_X_Atom atom;
-       unsigned char *in_pid = NULL;
-       int num;
-
-       atom = ecore_x_atom_get("X_CLIENT_PID");
-       if (ecore_x_window_prop_property_get(win, atom, ECORE_X_ATOM_CARDINAL,
-                               sizeof(int), &in_pid, &num) == EINA_FALSE) {
-               if(in_pid != NULL) {
-                       free(in_pid);
-                       in_pid = NULL;
-               }
-               if (ecore_x_netwm_pid_get(win, &pid) == EINA_FALSE) {
-                       _E("Failed to get PID from a window 0x%X", win);
-                       return -EINVAL;
-               }
-       } else {
-               pid = *(int *)in_pid;
-               free(in_pid);
-       }
-
-       return pid;
-}
-
-static Eina_Bool __proc_deiconify_cb(void *data, int type, void *event)
-{
-       Ecore_X_Event_Client_Message *ev;
-       int pid, oom_score_adj;
-
-       ev = event;
-
-       if (ev->format != 32)
-               return ECORE_CALLBACK_RENEW;
-       if (ev->message_type == ECORE_X_ATOM_E_DEICONIFY_APPROVE)
-       {
-               pid = _get_pid(ev->win);
-
-               _D("pid : %d received ediconify approve", pid);
-
-               if (proc_get_oom_score_adj(pid, &oom_score_adj) < 0) {
-                       _E("Failed to get oom_score_adj");
-                       return ECORE_CALLBACK_RENEW;
-               }
-
-               if (oom_score_adj >= OOMADJ_BACKGRD_UNLOCKED) {
-                       /* init oom_score_value */
-                       proc_set_oom_score_adj(pid, OOMADJ_INIT);
-               }
-       }
-
-       return ECORE_CALLBACK_RENEW;
-
-}
-
-static Eina_Bool __proc_visibility_cb(void *data, int type, void *event)
-{
-       Ecore_X_Event_Window_Visibility_Change *ev;
-       int pid, oom_score_adj;
-
-       ev = event;
-
-       pid = _get_pid(ev->win);
-
-       _D("pid : %d, bvisibility : %d", pid, ev->fully_obscured);
-
-       if (proc_get_oom_score_adj(pid, &oom_score_adj) < 0) {
-               _E("Failed to get oom_score_adj");
-               return ECORE_CALLBACK_RENEW;
-       }
-
-       if (oom_score_adj >= OOMADJ_BACKGRD_UNLOCKED) {
-               /* init oom_score_value */
-               proc_set_oom_score_adj(pid, OOMADJ_INIT);
-       }
-
-       return ECORE_CALLBACK_RENEW;
-
-}
-
-int proc_add_visibiliry(int pid)
-{
-       int found;
-       Display *d;
-
-       if (proc_get_dbus_proc_state())
-               return RESOURCED_ERROR_NO_DATA;
-       d = XOpenDisplay(NULL);
-
-       if (d == NULL) {
-               _E("XOpenDisplay return NULL, pid = %d", pid);
-               return RESOURCED_ERROR_FAIL;
-       }
-
-       if (!a_pid)
-               a_pid = XInternAtom(d, "_NET_WM_PID", True);
-
-       found = __find_win(d, pid);
-
-       if (!found) {
-               XCloseDisplay(d);
-               errno = ENOENT;
-               return RESOURCED_ERROR_FAIL;
-       } else
-               _D("%d window added for pid = %d", found, pid);
-
-       return RESOURCED_ERROR_NONE;
-}
-
-
-int proc_win_status_init(void)
-{
-       ecore_x_init(NULL);
-       ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
-                                   __proc_deiconify_cb, NULL);
-
-       ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
-                                   __proc_visibility_cb, NULL);
-       return RESOURCED_ERROR_NONE;
-}
-
index f44783d..0b1dc8d 100644 (file)
@@ -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.
 /**
  * @file init.c
  * @desc Resourced initialization
- * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  **/
 
 #include "const.h"
+#include "counter.h"
 #include "edbus-handler.h"
-
+#include "cgroup.h"
 #include "init.h"
 #include "macro.h"
 #include "module-data.h"
 #include "proc-main.h"
 #include "proc-monitor.h"
+#include "swap-common.h"
 #include "trace.h"
 #include "version.h"
-#include "resourced.h"
 
 #include <Ecore.h>
 #include <getopt.h>
 #include <signal.h>
 
-static struct daemon_opts opts = {1};
+static struct daemon_opts opts = { 1,
+                                  1,
+                                  1,
+                                  COUNTER_UPDATE_PERIOD,
+                                  FLUSH_PERIOD,
+                                  RESOURCED_DEFAULT_STATE,
+                                  0};
+
+#define SWAP_MAX_ARG_SIZE 16
+
+static char swap_arg[SWAP_ARG_END][SWAP_MAX_ARG_SIZE] = { "swapoff",
+                                   "swapon",};
 
 static void print_root_usage()
 {
@@ -49,12 +60,21 @@ static void print_root_usage()
 
 static void print_usage()
 {
-       puts("resmand [Options]");
+       puts("resourced [Options]");
        puts("       Application options:");
+       printf
+           ("-u [--update-period] - time interval for updating,"
+            " %d by default\n", opts.update_period);
+       printf
+           ("-f [--flush-period] - time interval for storing data at database,"
+            "%d by default\n", opts.flush_period);
        printf("-s [--start-daemon] - start as daemon, %d by default\n",
               opts.start_daemon);
        puts("-v [--version] - program version");
        puts("-h [--help] - application help");
+       printf("-c string [--swapcontrol=string] - control swap policy and "
+              "select sting %s, %s by default\n",
+              swap_arg[SWAP_OFF], swap_arg[SWAP_ON]);
 }
 
 static void print_version()
@@ -65,15 +85,18 @@ static void print_version()
 
 static int parse_cmd(int argc, char **argv)
 {
-       const char *optstring = ":hv:s:w";
+       const char *optstring = ":hvu:s:f:cw";
        const struct option options[] = {
                {"help", no_argument, 0, 'h'},
                {"version", no_argument, 0, 'v'},
+               {"update-period", required_argument, 0, 'u'},
+               {"flush-period", required_argument, 0, 'f'},
                {"start-daemon", required_argument, 0, 's'},
+               {"swapcontrol", required_argument, 0, 'c'},
                {"enable-watchodg", no_argument, 0, 'w'},
                {0, 0, 0, 0}
        };
-       int longindex, retval;
+       int longindex, retval, i;
 
        while ((retval =
                getopt_long(argc, argv, optstring, options, &longindex)) != -1)
@@ -85,9 +108,27 @@ static int parse_cmd(int argc, char **argv)
                case 'v':
                        print_version();
                        return RESOURCED_ERROR_FAIL;
+               case 'u':
+                       opts.update_period = atoi(optarg);
+                       break;
+               case 'f':
+                       opts.flush_period = atoi(optarg);
+                       break;
                case 's':
                        opts.start_daemon = atoi(optarg);
                        break;
+               case 'c':
+                       for (i = 0; i < SWAP_ARG_END; i++)
+                               if (optarg && !strncmp(optarg, swap_arg[i],
+                                                      SWAP_MAX_ARG_SIZE)) {
+                                       opts.enable_swap = i;
+                                       _D("argment swaptype = %s",
+                                          swap_arg[i]);
+                                       break;
+                               }
+                       break;
+               case 'o':
+                       break;
                case 'w':
                        proc_set_watchdog_state(PROC_WATCHDOG_ENABLE);
                        break;
@@ -110,6 +151,20 @@ static int assert_root(void)
 
 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) {
+               /* save data on exit, it's impossible to do in fini
+                * module function, due it executes right after ecore stopped */
+               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);
+       }
+
        ecore_main_loop_quit();
 }
 
@@ -132,6 +187,7 @@ int resourced_init(struct daemon_arg *darg)
        ret_code = parse_cmd(darg->argc, darg->argv);
        ret_value_msg_if(ret_code < 0, RESOURCED_ERROR_FAIL,
                         "Error parse cmd arguments\n");
+       _D("argment swaptype = %s", swap_arg[opts.enable_swap]);
        add_signal_handler();
        edbus_init();
        return RESOURCED_ERROR_NONE;
@@ -145,3 +201,17 @@ int resourced_deinit(struct daemon_arg *darg)
                         "Invalid daemon argument\n");
        return RESOURCED_ERROR_NONE;
 }
+
+void set_daemon_net_block_state(const enum traffic_restriction_type rst_type,
+       const struct counter_arg *carg)
+{
+       ret_msg_if(carg == NULL,
+               "Please provide valid counter arg!");
+
+       if (rst_type == RST_SET)
+               opts.state |= RESOURCED_NET_BLOCKED_STATE; /* set bit */
+       else {
+               opts.state &=(~RESOURCED_NET_BLOCKED_STATE); /* nulify bit */
+               ecore_timer_thaw(carg->ecore_timer);
+       }
+}
index 8248b76..000406c 100644 (file)
@@ -29,6 +29,9 @@
 
 #include "resourced.h"
 
+#include "daemon-options.h"
+#include "transmission.h"
+
 struct daemon_arg {
        int argc;
        char **argv;
@@ -39,4 +42,9 @@ int resourced_init(struct daemon_arg *darg);
 
 int resourced_deinit(struct daemon_arg *darg);
 
+struct counter_arg;
+
+void set_daemon_net_block_state(const enum traffic_restriction_type rst_type,
+       const struct counter_arg* carg);
+
 #endif /* _RESOURCED_INIT_H */
index c410072..f25f13a 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <Ecore.h>
 #include <mcheck.h>
+#include <systemd/sd-daemon.h>
 
 int main(int argc, char **argv)
 {
@@ -50,10 +51,13 @@ int main(int argc, char **argv)
        ret_value_msg_if(ret_code < 0, ret_code,
                         "Resourced initialization failed\n");
        init_modules_arg(&marg, &darg);
+       modules_check_runtime_support(&marg);
        modules_init(&marg);
        ret_code = resourced_proc_init(darg.opts);
        if (ret_code < 0)
                _E("Proc init failed");
+       sd_notify(0, "READY=1");
+
        ecore_main_loop_begin();
        modules_exit(&marg);
        resourced_deinit(&darg);
diff --git a/src/swap/swap.c b/src/swap/swap.c
new file mode 100644 (file)
index 0000000..740bed6
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * 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 swap.c
+ * @desc swap process
+ */
+
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "edbus-handler.h"
+#include "swap-common.h"
+#include "notifier.h"
+#include "proc-process.h"
+
+#include <resourced.h>
+#include <trace.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#define MAX_SWAP_VICTIMS               16
+
+#define MEMCG_PATH                     "/sys/fs/cgroup/memory"
+#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 SWAP_ON_EXEC_PATH              "/sbin/swapon"
+#define SWAP_OFF_EXEC_PATH             "/sbin/swapoff"
+
+#define SIGNAL_NAME_SWAP_TYPE          "SwapType"
+#define SIGNAL_NAME_SWAP_START_PID     "SwapStartPid"
+
+#define SWAPFILE_NAME                  "/dev/zram0"
+
+#define SWAP_PATH_MAX                  100
+
+#define MBtoB(x)                       (x<<20)
+#define MBtoPage(x)                    (x<<8)
+
+#define BtoMB(x)                       ((x) >> 20)
+#define BtoPAGE(x)                     ((x) >> 12)
+
+#define SWAP_TIMER_INTERVAL            0.5
+#define SWAP_PRIORITY                  20
+
+#define SWAP_COUNT_MAX                 5
+
+struct swap_data_type {
+       enum swap_status_type    status_type;
+       unsigned long *args;
+};
+
+static int swapon;
+static pthread_mutex_t swap_mutex;
+static pthread_cond_t swap_cond;
+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();
+
+       ret_value_msg_if(modules_data == NULL, RESOURCED_ERROR_FAIL,
+                        "Invalid shared modules data\n");
+       return modules_data->swap_data.swaptype;
+}
+
+static void swap_set_swap_type(int type)
+{
+       struct shared_modules_data *modules_data = get_shared_modules_data();
+
+       ret_msg_if(modules_data == NULL,
+                        "Invalid shared modules data\n");
+       modules_data->swap_data.swaptype = type;
+}
+
+static int swap_check_swap_pid(int pid)
+{
+       char buf[SWAP_PATH_MAX] = {0,};
+       int swappid;
+       int ret = 0;
+       FILE *f;
+
+       f = fopen(SWAPCG_PROCS, "r");
+       if (!f) {
+               _E("%s open failed", SWAPCG_PROCS);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       while (fgets(buf, SWAP_PATH_MAX, f) != NULL) {
+               swappid = atoi(buf);
+               if (swappid == pid) {
+                       ret = swappid;
+                       break;
+               }
+       }
+       fclose(f);
+       return ret;
+}
+
+static int swap_check_swap_cgroup(void)
+{
+       char buf[SWAP_PATH_MAX] = {0,};
+       int ret = SWAP_FALSE;
+       FILE *f;
+
+       f = fopen(SWAPCG_PROCS, "r");
+       if (!f) {
+               _E("%s open failed", SWAPCG_PROCS);
+               return RESOURCED_ERROR_FAIL;
+       }
+       while (fgets(buf, SWAP_PATH_MAX, f) != NULL) {
+               ret = SWAP_TRUE;
+               break;
+       }
+       fclose(f);
+       return ret;
+}
+
+static int swap_thread_do(FILE *procs, FILE *usage_in_bytes, FILE *force_reclaim)
+{
+       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;
+
+       /* check swap cgroup count */
+       while (fgets(buf, SWAP_PATH_MAX, procs) != NULL) {
+               pid_t tpid = 0;
+               int toom = 0;
+               int ret;
+
+               if (!pid) {
+                       tpid = atoi(buf);
+
+                       if (proc_get_oom_score_adj(tpid, &toom) < 0) {
+                              _D("pid(%d) was already terminated", tpid);
+                              continue;
+                       }
+
+                       if (toom < OOMADJ_BACKGRD_UNLOCKED)
+                              continue;
+
+                       ret = proc_get_cmdline(tpid, appname);
+                       if (ret == RESOURCED_ERROR_FAIL)
+                              continue;
+
+                       pid = tpid;
+               }
+               swap_cg_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);
+       }
+
+       /* cacluate reclaim size by usage and swap cgroup count */
+       if (fgets(buf, 32, usage_in_bytes) == NULL)
+               return RESOURCED_ERROR_FAIL;
+
+       usage = (unsigned long)atol(buf);
+
+       nr_to_reclaim = BtoPAGE(usage) >> ((swap_cg_cnt >> 1) + 1);
+
+       /* set reclaim size */
+       size = sprintf(buf, "%lu", nr_to_reclaim);
+       if (fwrite(buf, 1, size, force_reclaim) != size)
+               _E("fwrite %s\n", buf);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void *swap_thread_main(void * data)
+{
+       FILE *procs = NULL;
+       FILE *usage_in_bytes = NULL;
+       FILE *force_reclaim = NULL;
+
+       setpriority(PRIO_PROCESS, 0, SWAP_PRIORITY);
+
+       if (procs == NULL) {
+               procs = fopen(SWAPCG_PROCS, "r");
+               if (procs == NULL) {
+                       _E("%s open failed", SWAPCG_PROCS);
+                       return NULL;
+               }
+       }
+
+       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;
+               }
+       }
+
+       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;
+               }
+       }
+
+       while (1) {
+               pthread_mutex_lock(&swap_mutex);
+               pthread_cond_wait(&swap_cond, &swap_mutex);
+
+               /*
+                * when signalled by main thread, it starts
+                * swap_thread_do().
+                */
+               _I("swap thread conditional signal received");
+
+               fseek(procs, 0, SEEK_SET);
+               fseek(usage_in_bytes, 0, SEEK_SET);
+               fseek(force_reclaim, 0, SEEK_SET);
+
+               _D("swap_thread_do start");
+               swap_thread_do(procs, usage_in_bytes, force_reclaim);
+               _D("swap_thread_do end");
+               pthread_mutex_unlock(&swap_mutex);
+       }
+
+       if (procs)
+               fclose(procs);
+       if (usage_in_bytes)
+               fclose(usage_in_bytes);
+       if (force_reclaim)
+               fclose(force_reclaim);
+
+       return NULL;
+}
+
+static Eina_Bool swap_send_signal(void *data)
+{
+       int ret;
+
+       _D("swap timer callback function start");
+
+       /* signal to swap_start to start swap */
+       ret = pthread_mutex_trylock(&swap_mutex);
+
+       if (ret)
+               _E("pthread_mutex_trylock fail : %d, errno : %d", ret, errno);
+       else {
+               pthread_cond_signal(&swap_cond);
+               _I("send signal to swap thread");
+               pthread_mutex_unlock(&swap_mutex);
+       }
+
+       _D("swap timer delete");
+
+       ecore_timer_del(swap_timer);
+       swap_timer = NULL;
+
+       return ECORE_CALLBACK_CANCEL;
+}
+
+static int swap_start(void *data)
+{
+       if (swap_timer == NULL) {
+               _D("swap timer start");
+               swap_timer =
+                       ecore_timer_add(SWAP_TIMER_INTERVAL, swap_send_signal, (void *)NULL);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int swap_thread_create(void)
+{
+       int ret = RESOURCED_ERROR_NONE;
+       pthread_t pth;
+
+       pthread_mutex_init(&swap_mutex, NULL);
+       pthread_cond_init(&swap_cond, NULL);
+
+       ret = pthread_create(&pth, NULL, &swap_thread_main, (void*)NULL);
+       if (ret) {
+               _E("pthread creation for swap_thread failed\n");
+               return ret;
+       } else {
+               pthread_detach(pth);
+       }
+
+       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)
+{
+       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,};
+
+       f = fopen(SWAPCG_PROCS, "w");
+       if (!f) {
+               _E("Fail to %s file open", 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;
+}
+
+static void swap_start_pid_edbus_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int ret;
+       pid_t pid;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_SWAP, SIGNAL_NAME_SWAP_START_PID);
+       if (ret == 0) {
+               _D("there is no swap type signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       _I("swap cgroup entered : pid : %d", (int)pid);
+       swap_move_swap_cgroup(&pid);
+
+       if (get_swap_status() == SWAP_OFF)
+                       restart_swap(NULL);
+       swap_start(NULL);
+}
+
+static void swap_type_edbus_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int type;
+
+       if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_SWAP, SIGNAL_NAME_SWAP_TYPE) == 0) {
+               _D("there is no swap type signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID) == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       switch (type) {
+       case 0:
+               if (swap_get_swap_type() != SWAP_OFF) {
+                       if (swapon)
+                               swap_off();
+                       swap_set_swap_type(type);
+               }
+               break;
+       case 1:
+               if (swap_get_swap_type() != SWAP_ON) {
+                       restart_swap(NULL);
+                       swap_set_swap_type(type);
+               }
+               break;
+       default:
+               _D("It is not valid swap type : %d", type);
+               break;
+       }
+}
+
+static DBusMessage *edbus_getswaptype(E_DBus_Object *obj, DBusMessage *msg)
+{
+       DBusMessageIter iter;
+       DBusMessage *reply;
+       int state;
+
+       state = swap_get_swap_type();
+
+       reply = dbus_message_new_method_return(msg);
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &state);
+
+       return reply;
+}
+
+static struct edbus_method edbus_methods[] = {
+       { "GetSwapType",   NULL,   "i", edbus_getswaptype },
+       /* Add methods here */
+};
+
+static void swap_dbus_init(void)
+{
+       resourced_ret_c ret;
+
+       register_edbus_signal_handler(RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
+                       SIGNAL_NAME_SWAP_TYPE,
+                   (void *)swap_type_edbus_signal_handler);
+       register_edbus_signal_handler(RESOURCED_PATH_SWAP, RESOURCED_INTERFACE_SWAP,
+                       SIGNAL_NAME_SWAP_START_PID,
+                   (void *)swap_start_pid_edbus_signal_handler);
+
+       ret = edbus_add_methods(RESOURCED_PATH_SWAP, edbus_methods,
+                         ARRAY_SIZE(edbus_methods));
+
+       ret_msg_if(ret != RESOURCED_ERROR_NONE,
+               "DBus method registration for %s is failed",
+                       RESOURCED_PATH_SWAP);
+}
+
+static int swap_init(void)
+{
+       int ret;
+
+       ret = swap_thread_create();
+       if (ret) {
+               _E("swap thread create failed");
+               return ret;
+       }
+
+       _I("swap_init : %d", swap_get_swap_type());
+
+       swap_dbus_init();
+
+       return ret;
+}
+
+static int swap_check_node(void)
+{
+       FILE *procs = NULL;
+       FILE *usage_in_bytes = NULL;
+       FILE *force_reclaim = NULL;
+
+       procs = fopen(SWAPCG_PROCS, "r");
+       if (procs == NULL) {
+               _E("%s open failed", SWAPCG_PROCS);
+               return RESOURCED_ERROR_NO_DATA;
+       }
+
+       fclose(procs);
+
+       usage_in_bytes = fopen(SWAPCG_USAGE, "r");
+       if (usage_in_bytes == NULL) {
+               _E("%s open failed", SWAPCG_USAGE);
+               return RESOURCED_ERROR_NO_DATA;
+       }
+
+       fclose(usage_in_bytes);
+
+       force_reclaim = fopen(SWAPCG_RECLAIM, "w");
+       if (force_reclaim == NULL) {
+               _E("%s open failed", SWAPCG_RECLAIM);
+               return RESOURCED_ERROR_NO_DATA;
+       }
+
+       fclose(force_reclaim);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+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;
+
+       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/timer-slack/timer-slack.c b/src/timer-slack/timer-slack.c
new file mode 100644 (file)
index 0000000..1e0b1b7
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * 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 timer-slack.c
+ * @desc control timer about timer-slack cgroup
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ */
+
+#include "macro.h"
+#include "module.h"
+#include "module-data.h"
+#include "edbus-handler.h"
+#include "resourced.h"
+#include "trace.h"
+#include "vconf.h"
+#include "cgroup.h"
+#include "config-parser.h"
+#include "const.h"
+#include "timer-slack.h"
+#include "notifier.h"
+#include "proc-main.h"
+#include "proc-process.h"
+
+#include <resourced.h>
+#include <trace.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#define TIMER_EXCLUDE_CGROUP   "exclude"
+#define TIMER_SERVICE_CGROUP   "service"
+#define TIMER_BACKGRD_CGROUP   "background"
+#define TIMER_STATUS_LCDOFF    "LCDOFF"
+#define TIMER_SLACK_ROOT               NULL
+#define TIMER_STATUS_POWERSAVING       "POWERSAVING"
+
+#define TIMER_CONF_FILE                "/etc/resourced/timer-slack.conf"
+#define EXCLUDE_CONF_SECTION           "EXCLUDE_TIMER_SLACK"
+#define EXCLUDE_CONF_NAME      "EXCLUDE_PROC_NAME"
+
+#define TIMER_SLACK_MODE       "/timer_slack.timer_mode"
+#define TIMER_SLACK_VALUE      "/timer_slack.min_slack_ns"
+
+struct timer_slack_class {
+       char *name;
+       int timer_mode;
+       int slack_value;
+};
+
+enum {
+       TIMER_SLACK_DEFAULT,
+       TIMER_SLACK_SERVICE,
+       TIMER_SLACK_BACKGROUND,
+       TIMER_SLACK_LCDOFF,
+       TIMER_SLACK_POWERSAVIG,
+       TIMER_SLACK_MAX,
+};
+
+static struct timer_slack_class timer_slack[TIMER_SLACK_MAX] = {
+       {"DEFAULT", 0, 0},
+       {TIMER_SERVICE_CGROUP, 0, 0},
+       {TIMER_BACKGRD_CGROUP, 0, 0},
+       {TIMER_STATUS_LCDOFF, 0, 0},
+       {TIMER_STATUS_POWERSAVING, 0, 0},
+};
+
+static int current_root_timer_state = TIMER_SLACK_DEFAULT;
+
+static const struct module_ops timer_modules_ops;
+static const struct module_ops *timer_ops;
+
+static int timer_slack_write(char *sub_cgroup, char *node, int val)
+{
+       char path_buf[MAX_PATH_LENGTH];
+       int ret;
+       if (sub_cgroup) {
+               strncpy(path_buf, TIMER_CGROUP_PATH, sizeof(TIMER_CGROUP_PATH));
+               strcat(path_buf, "/");
+               strcat(path_buf, sub_cgroup);
+               ret = cgroup_write_node(path_buf, node, val);
+       } else
+               ret = cgroup_write_node(TIMER_CGROUP_PATH, node, val);
+       return ret;
+}
+
+static int launch_service(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       int ret;
+       ret = timer_slack_write(TIMER_SERVICE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
+       _I("move to service timer slack cgroup : pid (%d), ret (%d)", p_data->pid, ret);
+       return ret;
+}
+
+static int wakeup_timer_state(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       int ret;
+       ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
+       return ret;
+}
+
+static int background_timer_state(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       int ret;
+       ret = timer_slack_write(TIMER_BACKGRD_CGROUP, CGROUP_FILE_NAME, p_data->pid);
+       return ret;
+}
+
+static int active_timer_state(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       int ret;
+       ret = timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, p_data->pid);
+       return ret;
+}
+
+static int inactive_timer_state(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       int ret;
+       ret = timer_slack_write(TIMER_SLACK_ROOT, CGROUP_FILE_NAME, p_data->pid);
+       return ret;
+}
+
+static int timer_lcd_off(void *data)
+{
+       if (current_root_timer_state == TIMER_SLACK_DEFAULT) {
+               timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
+                           timer_slack[TIMER_SLACK_LCDOFF].timer_mode);
+               timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
+                           timer_slack[TIMER_SLACK_LCDOFF].slack_value);
+       }
+       current_root_timer_state = TIMER_SLACK_LCDOFF;
+       return RESOURCED_ERROR_NONE;
+}
+
+static int timer_lcd_on(void *data)
+{
+       if (current_root_timer_state == TIMER_SLACK_LCDOFF) {
+               timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_MODE,
+                           timer_slack[TIMER_SLACK_DEFAULT].timer_mode);
+               timer_slack_write(TIMER_SLACK_ROOT, TIMER_SLACK_VALUE,
+                           timer_slack[TIMER_SLACK_DEFAULT].slack_value);
+               current_root_timer_state = TIMER_SLACK_DEFAULT;
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static void set_default_cgroup_value(void)
+{
+       int i;
+       char *cgroup;
+       for (i = 0; i < TIMER_SLACK_MAX; i++) {
+               if (i == TIMER_SLACK_DEFAULT)
+                       cgroup = TIMER_SLACK_ROOT;
+               else if (i == TIMER_SLACK_SERVICE)
+                       cgroup = TIMER_SERVICE_CGROUP;
+               else if (i == TIMER_SLACK_BACKGROUND)
+                       cgroup = TIMER_BACKGRD_CGROUP;
+               else
+                       continue;
+               timer_slack_write(cgroup, TIMER_SLACK_MODE, timer_slack[i].timer_mode);
+               timer_slack_write(cgroup, TIMER_SLACK_VALUE, timer_slack[i].slack_value);
+       }
+}
+
+static int load_timer_config(struct parse_result *result, void *user_data)
+{
+       int i;
+       pid_t pid = 0;
+
+       if (!result)
+               return -EINVAL;
+
+       if (!strcmp(result->section, EXCLUDE_CONF_SECTION)) {
+               if (strcmp(result->name, EXCLUDE_CONF_NAME))
+                       return RESOURCED_ERROR_NO_DATA;
+               pid = find_pid_from_cmdline(result->value);
+               if (pid > 0)
+                       timer_slack_write(TIMER_EXCLUDE_CGROUP, CGROUP_FILE_NAME, pid);
+       } else {
+               for (i = 0; i < TIMER_SLACK_MAX; i++) {
+                       if (strcmp(result->section, timer_slack[i].name))
+                               continue;
+                       if (!strcmp(result->name, "timer_mode"))
+                               timer_slack[i].timer_mode = atoi(result->value);
+                       if (!strcmp(result->name, "min_slack_ns"))
+                               timer_slack[i].slack_value = atoi(result->value);
+               }
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static void timer_slack_cgroup_init(void)
+{
+       make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_EXCLUDE_CGROUP, NULL);
+       make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_SERVICE_CGROUP, NULL);
+       make_cgroup_subdir(TIMER_CGROUP_PATH, TIMER_BACKGRD_CGROUP, NULL);
+
+       config_parse(TIMER_CONF_FILE, load_timer_config, NULL);
+       set_default_cgroup_value();
+}
+
+static int resourced_timer_slack_check_runtime_support(void *data)
+{
+       DIR *dir = 0;
+
+       dir = opendir(TIMER_CGROUP_PATH);
+
+       if (dir) {
+               closedir(dir);
+               return RESOURCED_ERROR_NONE;
+       }
+       return RESOURCED_ERROR_NO_DATA;
+}
+
+static int resourced_timer_slack_init(void *data)
+{
+       timer_ops = &timer_modules_ops; 
+
+       timer_slack_cgroup_init();
+
+       register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
+       register_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
+       register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
+       register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
+       register_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
+       register_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
+       register_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
+       register_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_timer_slack_finalize(void *data)
+{
+       unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, launch_service);
+       unregister_notifier(RESOURCED_NOTIFIER_APP_RESUME, wakeup_timer_state);
+       unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, wakeup_timer_state);
+       unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, background_timer_state);
+       unregister_notifier(RESOURCED_NOTIFIER_APP_ACTIVE, active_timer_state);
+       unregister_notifier(RESOURCED_NOTIFIER_APP_INACTIVE, inactive_timer_state);
+       unregister_notifier(RESOURCED_NOTIFIER_LCD_ON, timer_lcd_on);
+       unregister_notifier(RESOURCED_NOTIFIER_LCD_OFF, timer_lcd_off);
+       return RESOURCED_ERROR_NONE;
+}
+
+static const struct module_ops timer_modules_ops = {
+       .priority = MODULE_PRIORITY_NORMAL,
+       .name = TIMER_MODULE_NAME,
+       .init = resourced_timer_slack_init,
+       .exit = resourced_timer_slack_finalize,
+       .check_runtime_support = resourced_timer_slack_check_runtime_support,
+};
+MODULE_REGISTER(&timer_modules_ops)
diff --git a/src/timer-slack/timer-slack.conf b/src/timer-slack/timer-slack.conf
new file mode 100644 (file)
index 0000000..2a35051
--- /dev/null
@@ -0,0 +1,28 @@
+[EXCLUDE_TIMER_SLACK]
+# predefined excluded process list
+EXCLUDE_PROC_NAME=Xorg
+EXCLUDE_PROC_NAME=enlightenment
+EXCLUDE_PROC_NAME=dbus-daemon
+EXCLUDE_PROC_NAME=amd
+EXCLUDE_PROC_NAME=alarm-server
+EXCLUDE_PROC_NAME=pulseaudio
+EXCLUDE_PROC_NAME=deviced
+EXCLUDE_PROC_NAME=system-syspopup
+EXCLUDE_PROC_NAME=w-home
+
+# set proper value about each timer slack cgroup
+[LCDOFF]
+timer_mode=1
+min_slack_ns=0
+
+[POWERSAVING]
+timer_mode=1
+min_slack_ns=100000000
+
+[service]
+timer_mode=1
+min_slack_ns=0
+
+[background]
+timer_mode=1
+min_slack_ns=100000000
similarity index 65%
rename from src/common/cpu-common.h
rename to src/timer-slack/timer-slack.h
index cbd4ad0..e6a3368 100644 (file)
  */
 
 /**
- * @file cpu-common.h
- * @desc cpu common process
+ * @file timer-slack.h
+ * @desc timer slack common process
  **/
 
-#ifndef __CPU_COMMON_H__
-#define __CPU_COMMON_H__
+#ifndef __TIMER_SLACK_COMMON_H__
+#define __TIMER_SLACK_COMMON_H__
 
 #include <sys/types.h>
+#define TIMER_CGROUP_PATH              "/sys/fs/cgroup/timer_slack"
+#define TIMER_MODULE_NAME              "timer"
 
-enum cpu_control_type {
-       CPU_SET_LAUNCH,
-       CPU_SET_FOREGROUND,
-       CPU_SET_BACKGROUND
+enum timer_cgroup_type {
+       TIMER_CGROUP_DEFAULT,
+       TIMER_CGROUP_EXCLUDE,
+       TIMER_CGROUP_SERVICE,
+       TIMER_CGROUP_BACKGRD,
 };
 
-struct cpu_data_type {
-       enum cpu_control_type control_type;
-       pid_t pid;
-};
-
-int cpu_control(enum cpu_control_type type, pid_t pid);
-
-#endif /* __CPU_COMMON_H__ */
+#endif /* __TIMER_SLACK_COMMON_H__ */
diff --git a/src/utils/cgroup-test.c b/src/utils/cgroup-test.c
new file mode 100644 (file)
index 0000000..af6dc3d
--- /dev/null
@@ -0,0 +1,41 @@
+#include <config.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "net-cls-cgroup.h"
+
+int64_t timespecDiff(struct timespec *time_a, struct timespec *time_b)
+{
+       return ((time_a->tv_sec * 1000000000) + time_a->tv_nsec) -
+           ((time_b->tv_sec * 1000000000) + time_b->tv_nsec);
+}
+
+#define START_MEASURE {\
+       struct timespec start, end; \
+       clock_gettime(CLOCK_MONOTONIC, &start);
+
+#define END_MEASURE \
+       clock_gettime(CLOCK_MONOTONIC, &end); \
+       int64_t timeElapsed = timespecDiff(&end, &start);\
+       printf("time diff %"PRId64"\n", timeElapsed); \
+       }
+
+#define TEST_NUM 100
+
+int main(void)
+{
+       int i = 0;
+       char cgroup_name[128];
+
+       printf("start measure");
+       for (; i < TEST_NUM; ++i) {
+               sprintf(cgroup_name, "com.samsung.browser%d", i);
+               START_MEASURE
+               make_net_cls_cgroup_with_pid(i, cgroup_name);
+               END_MEASURE
+       }
+
+       return 0;
+}
diff --git a/src/utils/database.c b/src/utils/database.c
new file mode 100644 (file)
index 0000000..b1cbbfc
--- /dev/null
@@ -0,0 +1,30 @@
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "app-stat.h"
+#include "macro.h"
+#include "storage.h"
+
+int main(int argc, char **argv)
+{
+       struct application_stat requests[] = {
+               {"emacs", 24, 42},
+               {"vim", 43, 49},
+               {"emacs", 52, 56}
+       };/*It's not standards compliant, but more robust */
+
+       int index;
+       struct application_stat_tree *app_tree = create_app_stat_tree();
+
+       init_database("./base.db");
+
+       for (index = 0; index != ARRAY_SIZE(requests); ++index)
+               g_tree_insert((GTree *) app_tree->tree,
+                       (gpointer)index, (gpointer)(requests + index));
+
+       store_result(app_tree, 0); /*0 time period means alway perform storing*/
+       close_database();
+       free_app_stat_tree(app_tree);
+       return 0;
+}
diff --git a/src/utils/datausage-tool.c b/src/utils/datausage-tool.c
new file mode 100644 (file)
index 0000000..2419677
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * 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 datausage-tool.c
+ * @desc Implement Performance API. Command line utility.
+ *
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "data_usage.h"
+#include "resourced.h"
+#include "rd-network.h"
+#include "const.h"
+#include "iface.h"
+#include "config.h"
+#include "trace.h"
+#include "version.h"
+
+enum run_rsml_cmd {
+       UNDEFINED,
+       RESOURCED_APPLY,
+       RESOURCED_GET,
+       RESOURCED_DATA_USAGE,
+       RESOURCED_DATA_USAGE_DETAILS,
+       RESOURCED_EXCLUDE,
+       RESOURCED_REVERT,
+       RESOURCED_GET_RESTRICTIONS,
+       RESOURCED_SET_OPTIONS,
+       RESOURCED_GET_OPTIONS,
+       RESOURCED_SET_QUOTA,
+       RESOURCED_REMOVE_QUOTA,
+       RESOURCED_RESTRICTION_STATE,
+};
+
+struct arg_param {
+       data_usage_selection_rule du_rule;
+       int64_t rcv_limit;
+       int64_t send_limit;
+       resourced_roaming_type roaming_type;
+       char *app_id;
+};
+
+static resourced_ret_c convert_roaming(const char *str,
+       resourced_roaming_type *roaming)
+{
+       if (!str)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (!strcmp(optarg, "enabled")) {
+               *roaming = RESOURCED_ROAMING_ENABLE;
+               return RESOURCED_ERROR_NONE;
+       }
+
+       if (!strcmp(optarg, "disabled")) {
+               *roaming = RESOURCED_ROAMING_DISABLE;
+               return RESOURCED_ERROR_NONE;
+       }
+
+       if (!strcmp(optarg, "unknown")) {
+               *roaming = RESOURCED_ROAMING_UNKNOWN;
+               return RESOURCED_ERROR_NONE;
+       }
+       return RESOURCED_ERROR_INVALID_PARAMETER;
+}
+
+static void print_version()
+{
+       printf("Version number: %d.%d-%d\n", MAJOR_VERSION, MINOR_VERSION,
+               PATCH_VERSION);
+}
+
+static void print_usage()
+{
+       puts("run_rsml [Options]");
+       puts("       Application options:");
+       puts(" possible ordering values: ");
+       puts("\t\tappid - order by application id (package name) "
+            "in ascending");
+       puts("\t\tappiddesc - order by application id (package name) "
+            "in descending");
+       puts("\t\tiface - ascending ordering by network interface name");
+       puts("\t\tifacedesc - descending ordering by network interface name");
+       puts("-a [--apply-rst] <package name> - apply restriction");
+       puts("-e [--exclude-rst] <package name> - exclude restriction");
+       puts("-R [--restrictions] <incoming>,<outgoing> "
+            "- restrictions to apply");
+       puts("-r [--revert-rst] <package name> - revert restriction");
+       puts("-l [--list-app-rst] - list of restricted applications");
+       puts("-g [--get] - get counters and restriction for application");
+       puts("-v [--version] - program version");
+       puts("-h [--help] - application help");
+       puts("-u [--data-usage] - data usage");
+       puts("-f [--from] <timestamp> - starting timestamp "
+            "for data usage requests");
+       puts("-t [--to] <timestamp> - ending timestamp "
+            "for data usage requests");
+       puts("-i [--interface] <iface> - interface name");
+       puts("-d [--data-usage-details] [<appid>] - data usage details "
+            "total/for application");
+       puts("-G [--granularity] <seconds> - split data usage results "
+            "into chunks of <seconds>");
+       puts("-O [--options] <set|get> set or get options");
+       puts(" In case of set options:");
+       puts(" -W [--wifi] <1|0> enable or disable wifi");
+       puts(" -D [--datacall] <1|0> enable or disable datacall");
+       puts(" -T [--datausagetimer] <1|0> enable or disable datausage timer");
+       puts(" -L [--datacalllogging] <1|0> enable or disable datacall logging");
+       puts(" -M [--roaming] <enalbled|disabled|unknown> enable or disable "
+               " roaming, unknown by default");
+       puts(" -q [--quota] <appid> ");
+       puts(" -Q [--remove-quota] <appid> ");
+       puts(" -s [--rst-state] <pkgid> ");
+}
+
+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 struct option options[] = {
+               {"help", no_argument, 0, 'h'},
+               {"list-app-rst", no_argument, 0, 'l'},
+               {"version", no_argument, 0, 'v'},
+               {"apply-rst", required_argument, 0, 'a'},
+               {"exclude-rst", required_argument, 0, 'e'},
+               {"revert-rst", required_argument, 0, 'r'},
+               {"get", required_argument, 0, 'g'},
+               {"data-usage", no_argument, 0, 'u'},
+               {"from", required_argument, 0, 'f'},
+               {"to", required_argument, 0, 't'},
+               {"interface", required_argument, 0, 'i'},
+               {"data-usage-details", optional_argument, 0, 'd'},
+               {"granularity", required_argument, 0, 'G'},
+               {"restrictions", required_argument, 0, 'R'},
+               {"options", required_argument, 0, 'O'},
+               {"quota", required_argument, 0, 'q'},
+               {"remove-quota", required_argument, 0, 'Q'},
+               {"roaming", required_argument, 0, 'M'},
+               {"rst-state", required_argument, 0, 's'},
+               {0, 0, 0, 0}
+       };
+
+       int longindex, retval;
+       enum run_rsml_cmd cmd = UNDEFINED;
+       resourced_iface_type iftype;
+
+       while ((retval =
+               getopt_long(argc, argv, optstring, options,
+                           &longindex)) != -1) {
+               switch (retval) {
+               case 'h':
+               case '?':
+                       print_usage();
+                       exit(EXIT_SUCCESS);
+               case 'v':
+                       print_version();
+                       exit(EXIT_SUCCESS);
+               case 'a':
+                       if (!optarg) {
+                               printf("apply-rst option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_APPLY;
+                       param->app_id = strdup(optarg);
+                       break;
+               case 'e':
+                       if (!optarg) {
+                               printf("exclude-rst option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_EXCLUDE;
+                       param->app_id = strdup(optarg);
+                       break;
+               case 'g':
+                       cmd = RESOURCED_GET;
+                       break;
+               case 'u':
+                       cmd = RESOURCED_DATA_USAGE;
+                       break;
+               case 'f':
+                       if (!optarg) {
+                               printf("from option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sscanf(optarg, "%ld", &param->du_rule.from) != 1) {
+                               printf("Failed to parse 'from' timestamp: %s\n",
+                                      optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 't':
+                       if (!optarg) {
+                               printf("to option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sscanf(optarg, "%ld", &param->du_rule.to) != 1) {
+                               printf("Failed to parse 'to' timestamp: %s\n",
+                                      optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 'i':
+                       if (!optarg) {
+                               printf("interface option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       iftype = convert_iftype(optarg);
+                       if (iftype == RESOURCED_IFACE_UNKNOWN) {
+                               printf("Unknown network interface!\n");
+                               exit(EXIT_FAILURE);
+                       }
+
+                       /* TODO change internal param structure */
+                       param->du_rule.iftype = iftype;
+                       break;
+               case 'M':
+                       if (!optarg) {
+                               printf("roaming option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       resourced_ret_c ret_code = convert_roaming(optarg,
+                               &param->roaming_type);
+
+                       if (ret_code != RESOURCED_ERROR_NONE) {
+                               printf("Wrong argument of roaming: %s, roaming "
+                                       "can only be enabled or disabled\n", optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 'd':
+                       cmd = RESOURCED_DATA_USAGE_DETAILS;
+                       if (optarg)
+                               param->app_id = strdup(optarg);
+                       break;
+               case 'G':
+                       if (!optarg) {
+                               printf("granularity option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sscanf(optarg, "%d", &param->du_rule.granularity) !=
+                           1) {
+                               printf("Failed to parse granularity: %s\n",
+                                      optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 'r':
+                       if (!optarg) {
+                               printf("revert-rst option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_REVERT;
+                       param->app_id = strdup(optarg);
+                       break;
+               case 'l':
+                       cmd = RESOURCED_GET_RESTRICTIONS;
+                       break;
+               case 'R':
+                       if (!optarg) {
+                               printf("restrictions option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (sscanf
+                           (optarg, "%jd,%jd",
+                            &param->rcv_limit,
+                            &param->send_limit) != 2) {
+                               printf("Failed to parse restrictions\n"
+                                      "expected 2 integer numbers separated with commas without spaces\n"
+                                      "got \"%s\"\n", optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+               case 'O':
+                       if (!optarg) {
+                               printf("options option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       if (optarg && strcmp(optarg, "set") == 0)
+                               cmd = RESOURCED_SET_OPTIONS;
+                       else if (optarg && strcmp(optarg, "get") == 0)
+                               cmd = RESOURCED_GET_OPTIONS;
+                       break;
+               case 'q':
+                       if (!optarg) {
+                               printf("Quota option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_SET_QUOTA;
+                       param->app_id = strdup(optarg);
+
+                       break;
+               case 'Q':
+                       if (!optarg) {
+                               printf("Remove quota option requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_REMOVE_QUOTA;
+                       param->app_id = strdup(optarg);
+                       break;
+               case 's':
+                       if (!optarg) {
+                               printf("Restriction state requeres an argument.");
+                               exit(EXIT_FAILURE);
+                       }
+                       cmd = RESOURCED_RESTRICTION_STATE;
+                       param->app_id = strdup(optarg);
+                       break;
+               default:
+                       printf("Unknown option %c\n", (char)retval);
+                       print_usage();
+                       exit(EXIT_FAILURE);
+               }
+       }
+       return cmd;
+}
+
+/* common callback for data usage and data usage details
+ * user_data is NULL for data usage
+ * user_data is a non-NULL
+ * (but not necessarily meaningful) for data usage details
+ */
+resourced_cb_ret data_usage_callback(const data_usage_info *info, void *user_data)
+{
+       /*TODO rewrite this hack*/
+       if (user_data)
+               printf("iftype %d\n", info->iftype);
+       else
+               printf("%s\n", 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));
+       } else
+               printf("<entire interval>\t");
+
+       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,
+              info->roaming, info->hw_net_protocol_type,
+              info->ifname);
+       return RESOURCED_CONTINUE;
+}
+
+static inline int is_valid_range32(const int64_t value)
+{
+       return value >= 0 && value <= 2147483647; /* 2Gb */
+}
+
+/* callback for restriction details
+ */
+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",
+               info->app_id ? info->app_id : UNKNOWN_APP,
+              info->iftype, info->rst_state,
+              info->rcv_limit, info->send_limit, info->roaming);
+       return RESOURCED_CONTINUE;
+}
+
+const char *state_representation[] = {
+       "UNDEFINDED",
+       "ACTIVATED",
+       "EXCLUDED",
+};
+
+const char *convert_restriction_state(network_restriction_state state) {
+       if (state <= NETWORK_RESTRICTION_UNDEFINDED
+               && state >= NETWORK_RESTRICTION_MAX_VALUE) {
+               fprintf(stderr, "state not in range %d", state);
+               return NULL;
+       }
+
+       return state_representation[state];
+}
+
+void print_restriction_state(resourced_restriction_state state)
+{
+       const char *state_str = convert_restriction_state(state);
+       if (state_str)
+               printf("\nRestriction state: %s\n", state_str);
+}
+
+int main(int argc, char **argv)
+{
+       int ret_code = 0;
+       struct arg_param param;
+       enum run_rsml_cmd cmd = UNDEFINED;
+       if (argc == 1) {
+               print_usage();
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&param, 0, sizeof(struct arg_param));
+       cmd = parse_cmd(argc, argv, &param);
+       switch (cmd) {
+       case RESOURCED_APPLY:
+       {
+               int err = 0;
+               resourced_net_restrictions net_rst = {0,};
+
+               if (!param.du_rule.iftype) {
+                       fprintf(stderr, "Apply restriction command requires -i\n");
+                       err = RESOURCED_ERROR_INVALID_PARAMETER;
+               }
+
+               if (!is_valid_range32(param.send_limit)) {
+                       fprintf(stderr, "Send limit should be in range 0 - 2Gb");
+                       err = RESOURCED_ERROR_INVALID_PARAMETER;
+               }
+               if (!is_valid_range32(param.rcv_limit)) {
+                       fprintf(stderr, "Rcv limit should be in range 0 - 2Gb");
+                       err = RESOURCED_ERROR_INVALID_PARAMETER;
+               }
+
+               if (err)
+                       return err;
+
+               net_rst.send_limit = param.send_limit;
+               net_rst.rcv_limit = param.rcv_limit;
+               net_rst.iftype = param.du_rule.iftype;
+
+               ret_code = set_net_restriction(param.app_id,
+                                                      &net_rst);
+               if (ret_code != RESOURCED_ERROR_NONE) {
+                       fprintf(stderr, "Failed to set restriction\n");
+                       return ret_code;
+               }
+
+               break;
+
+       }
+       case RESOURCED_EXCLUDE:
+       {
+               resourced_net_restrictions rst = {0,};
+               rst.iftype = param.du_rule.iftype;
+               rst.roaming = param.roaming_type;
+
+               ret_code = set_net_exclusion(param.app_id,
+                       &rst);
+               if (ret_code != RESOURCED_ERROR_NONE)
+                       return ret_code;
+               break;
+       }
+       case RESOURCED_DATA_USAGE:
+               if (param.du_rule.from && param.du_rule.to) {
+                       data_usage_foreach(&param.du_rule, data_usage_callback,
+                                          NULL);
+               } else {
+                       fprintf(stderr, "Data usage commands require both "
+                              "--from and --to\n");
+               }
+               break;
+       case RESOURCED_DATA_USAGE_DETAILS:
+               if (param.du_rule.from && param.du_rule.to) {
+                       /* see description for data_usage_callback above */
+                       data_usage_details_foreach(param.app_id, &param.du_rule,
+                                                  data_usage_callback,
+                                                  (void *)1);
+               } else {
+                       fprintf(stderr, "Data usage commands require both "
+                              "--from and --to\n");
+               }
+               break;
+       case RESOURCED_REVERT:
+               if (param.du_rule.iftype)
+                       ret_code = remove_restriction_by_iftype(
+                               param.app_id, param.du_rule.iftype);
+               else
+                       fprintf(stderr, "Revert restriction commands require -i\n");
+               if (ret_code != RESOURCED_ERROR_NONE)
+                       return ret_code;
+               break;
+       case RESOURCED_GET_RESTRICTIONS:
+               printf("Applications are restricted now:\n");
+               ret_code = restrictions_foreach(restriction_callback, NULL);
+               break;
+       case RESOURCED_SET_OPTIONS:
+       {
+               resourced_options options = {0};
+               ret_code = set_resourced_options(&options);
+               break;
+       }
+       case RESOURCED_GET_OPTIONS:
+       {
+               resourced_options options = {0};
+               ret_code = get_resourced_options(&options);
+               break;
+       }
+       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;
+               }
+
+               /* 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;
+               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.roaming_type =  param.roaming_type;
+               if (set_datausage_quota(param.app_id, &quota) !=
+                    RESOURCED_ERROR_NONE) {
+                               fprintf(stderr, "Failed to apply quota!\n");
+               }
+               break;
+       }
+       case RESOURCED_REMOVE_QUOTA:
+       {
+               struct datausage_quota_reset_rule rule = {0};
+
+               rule.app_id = param.app_id;
+               rule.iftype = param.du_rule.iftype;
+               rule.roaming = param.roaming_type;
+
+               if (remove_datausage_quota(&rule) != RESOURCED_ERROR_NONE) {
+                       fprintf(stderr, "Failed to remove quota!\n");
+               }
+               break;
+       }
+       case RESOURCED_RESTRICTION_STATE:
+       {
+               resourced_restriction_state state;
+               if (!param.du_rule.iftype) {
+                       fprintf(stderr, "Exclude restriction commands require -i\n");
+                       ret_code = RESOURCED_ERROR_INVALID_PARAMETER;
+                       break;
+               }
+
+               ret_code = get_restriction_state(param.app_id,
+                       param.du_rule.iftype, &state);
+
+               print_restriction_state(state);
+               break;
+       }
+       default:
+               ret_code = RESOURCED_ERROR_INVALID_PARAMETER;
+               break;
+       }
+
+       return ret_code;
+}
diff --git a/src/utils/hashtest.c b/src/utils/hashtest.c
new file mode 100644 (file)
index 0000000..e4fc481
--- /dev/null
@@ -0,0 +1,16 @@
+#include <glib.h>
+#include <stdio.h>
+static gboolean int_cmp(const void *ptr1, const void *ptr2)
+{
+       return (GPOINTER_TO_INT(ptr1) == GPOINTER_TO_INT(ptr2)) ? TRUE : FALSE;
+}
+
+int main(void)
+{
+       GHashTable *table = g_hash_table_new(g_direct_hash, int_cmp);
+       void *ptr = 0;
+       g_hash_table_insert(table, GINT_TO_POINTER(42), main);
+       ptr = g_hash_table_lookup(table, GINT_TO_POINTER(42));
+       printf("%p\n%p\n", ptr, main);
+       return 0;
+}
diff --git a/src/utils/iface-test.c b/src/utils/iface-test.c
new file mode 100644 (file)
index 0000000..05f245f
--- /dev/null
@@ -0,0 +1,9 @@
+
+
+#include "iface.h"
+
+int main(void)
+{
+       init_iftype();
+       return 0;
+}
diff --git a/src/utils/inodeuser.c b/src/utils/inodeuser.c
new file mode 100644 (file)
index 0000000..0e0159f
--- /dev/null
@@ -0,0 +1,9 @@
+#include <inode2pid.h>
+
+int main(int argc, char **argv)
+{
+       int index;
+       for (index = 0; index < 15; ++index)
+               update_inode_pid_map();
+       return 0;
+}
diff --git a/src/utils/monitored.c b/src/utils/monitored.c
new file mode 100644 (file)
index 0000000..fbe07e6
--- /dev/null
@@ -0,0 +1,11 @@
+#include "net-cls-cgroup.h"
+#include "macro.h"
+
+int main(int argc, char **argv)
+{
+       int_array *pids = get_monitored_pids();
+       array_foreach(key, int, pids) {
+               printf("%d\n", *key);
+       }
+       return 0;
+}
diff --git a/src/utils/portuser.c b/src/utils/portuser.c
new file mode 100644 (file)
index 0000000..2f917d9
--- /dev/null
@@ -0,0 +1,28 @@
+
+#include "inode2pid.h"
+#include "macro.h"
+#include "port2inode.h"
+#include "trace.h"
+
+static void forearch_get_pid(int inode)
+{
+       int pid;
+       _D("Related inode is: %d", inode);
+       pid = get_pid_from_inode(inode);
+       _D("Got pid : %d", pid);
+}
+
+int main(int argc, char **argv)
+{
+       const int port = 1580;
+       GArray *inodes;
+       int index;
+       for (index = 0; index != 15000; ++index)
+               update_port_inode_map();
+
+       inodes = get_inode_from_port(port, GRABBER_PROTO_TCP);
+       update_inode_pid_map();
+       for (index = 0; inodes && index != inodes->len; ++index)
+               forearch_get_pid(g_array_index(inodes, int, index));
+       return 0;
+}
diff --git a/src/utils/proc-stat-test.c b/src/utils/proc-stat-test.c
new file mode 100644 (file)
index 0000000..d24647b
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * resourced
+ *
+ * Lib for getting process statistics
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <proc_stat.h>
+
+
+
+int main(void)
+{
+       GArray *valid_proc_infos = NULL;
+       GArray *terminated_proc_infos = NULL;
+       proc_stat_system_time st_diff;
+
+       terminated_proc_infos = g_array_new(false, false, sizeof(proc_stat_process_info));
+       valid_proc_infos = g_array_new(false, false, sizeof(proc_stat_process_info));
+
+
+       proc_stat_init();
+
+       while (true) {
+
+               proc_stat_get_process_info(valid_proc_infos, terminated_proc_infos, NULL);
+               proc_stat_get_system_time_diff(&st_diff);
+
+               if (st_diff.total_time != 0) {
+
+                       double total_time = st_diff.total_time;
+
+                       printf("Total CPU Info : %3.2lf%%us %3.2lf%%sy %3.2lf%%ni %3.2lf%%id %3.2lf%%iowait %3.2lf%%irq %3.2lf%%softirq\n",
+                               (double)st_diff.user_time / total_time * 100,
+                               (double)st_diff.system_time / total_time * 100,
+                               (double)st_diff.nice_time / total_time * 100,
+                               (double)st_diff.idle_time / total_time * 100,
+                               (double)st_diff.iowait_time / total_time * 100,
+                               (double)st_diff.irq_time / total_time * 100,
+                               (double)st_diff.softirq_time / total_time * 100);
+
+                       unsigned int total, free;
+                       if (proc_stat_get_total_mem_size(&total) && proc_stat_get_free_mem_size(&free))
+                               printf("Total Memory Info : Total:%dMB Free:%dMB Used:%dMB\n", total, free, total - free);
+
+                       unsigned int i = 0;
+                       for (i = 0; i < valid_proc_infos->len; ++i) {
+                               proc_stat_process_info *ps = &g_array_index(valid_proc_infos, proc_stat_process_info, i);
+
+                               if ((ps->active) || (ps->fresh)) {
+                                       if (ps->fresh)
+                                               printf("N ");
+                                       else
+                                               printf("  ");
+
+                                       printf("[pid:%d\t name:%40s utime:%3.2lf%% stime:%3.2lf%% rss:%dKb\n",
+                                               ps->pid, ps->name,
+                                               (double)(ps->utime_diff)/(double)st_diff.total_time*100,
+                                               (double)(ps->stime_diff)/(double)st_diff.total_time*100,
+                                               ps->rss);
+                               }
+                       }
+
+                       for (i = 0; i < terminated_proc_infos->len; ++i) {
+
+                               proc_stat_process_info *ps = &g_array_index(terminated_proc_infos, proc_stat_process_info, i);
+
+                               printf("T ");
+                               printf("[pid:%d\t name:%40s\n",
+                                               ps->pid, ps->name);
+                       }
+
+               }
+
+               usleep(1000000);
+               g_array_set_size(valid_proc_infos, 0);
+               g_array_set_size(terminated_proc_infos, 0);
+
+               printf("-------------------------------------------------------------------------------\n");
+
+       }
+
+       if (valid_proc_infos) {
+               g_array_free(valid_proc_infos, true);
+               valid_proc_infos = NULL;
+       }
+
+
+       if (terminated_proc_infos) {
+               g_array_free(terminated_proc_infos, true);
+               terminated_proc_infos = NULL;
+       }
+
+       proc_stat_finalize();
+
+       return 0;
+}
diff --git a/src/utils/test-net-activity.c b/src/utils/test-net-activity.c
new file mode 100644 (file)
index 0000000..1fd7811
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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 testgrabbing.c
+ * @desc Functionality for testing ktgrabber communications
+ *     and related procedures
+ */
+
+#include "trace.h"
+
+#include <data_usage.h>
+#include <mcheck.h>
+#include <Ecore.h>
+
+resourced_cb_ret net_activity_func(struct net_activity_info *info)
+{
+       printf("%20s\t|%8d\t|%8d\t|%8d\t|\n", info->appid, info->iftype,
+              info->type, info->bytes);
+       return RESOURCED_CONTINUE;
+}
+
+int main(int argc, char **argv)
+{
+       resourced_ret_c ret;
+#ifdef DEBUG_ENABLED
+       mtrace();
+       mcheck(0);
+#endif
+       printf("%20s\t|%8s\t|%8s\t|%8s\t|\n", "appid", "iftype",
+              "type", "bytes");
+
+       ret = register_net_activity_cb(net_activity_func);
+       ecore_main_loop_begin();
+       return 0;
+}
diff --git a/src/utils/udp-client.c b/src/utils/udp-client.c
new file mode 100644 (file)
index 0000000..348bc9d
--- /dev/null
@@ -0,0 +1,42 @@
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "udp-common.h"
+
+int main(void)
+{
+       struct sockaddr_in remote_address;
+
+       int i, slen = sizeof(struct sockaddr_in);
+       char buf[BUF_SIZE];
+
+       int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (s == -1) {
+               perror("socket");
+               exit(1);
+       }
+
+       prepare_address(AF_INET, PORT, &remote_address);
+
+       if (inet_aton(SRV_IP, &remote_address.sin_addr) == 0) {
+               fprintf(stderr, "inet_aton() failed\n");
+               exit(1);
+       }
+       for (i = 0; i < PACKET_NUMBER; i++) {
+               printf("Sending packet %d\n", i);
+               sprintf(buf, "This is packet %d\n", i);
+               if (sendto(s, buf, BUF_SIZE, 0, (struct sockaddr *)&remote_address, slen) == -1) {
+                       perror("sendto()");
+                       exit(1);
+               }
+               sleep(WAIT_INTERVAL);
+       }
+
+       close(s);
+       return 0;
+}
diff --git a/src/utils/udp-common.c b/src/utils/udp-common.c
new file mode 100644 (file)
index 0000000..5a5cf1b
--- /dev/null
@@ -0,0 +1,11 @@
+#include <netinet/in.h>
+#include <string.h>
+
+#include "udp-common.h"
+
+void prepare_address(int family, int port, struct sockaddr_in *addr)
+{
+       memset((char *) addr, 0, sizeof(struct sockaddr_in));
+       addr->sin_family = family;
+       addr->sin_port = htons(port);
+}
diff --git a/src/utils/udp-common.h b/src/utils/udp-common.h
new file mode 100644 (file)
index 0000000..93961a0
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PERF_CONTROL_UTILS_UDP_COMMON_H
+#define _PERF_CONTROL_UTILS_UDP_COMMON_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#define BUF_SIZE 512
+#define PACKET_NUMBER 1000
+#define PORT 2012
+#define WAIT_INTERVAL 20
+#define SRV_IP "192.168.129.3"
+
+void prepare_address(int family, int port, struct sockaddr_in *addr);
+
+#endif /*_PERF_CONTROL_UTILS_UDP_COMMON_H*/
+
diff --git a/src/utils/udp-server.c b/src/utils/udp-server.c
new file mode 100644 (file)
index 0000000..78644aa
--- /dev/null
@@ -0,0 +1,44 @@
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "udp-common.h"
+
+int main(void)
+{
+       struct sockaddr_in local_address, remote_address;
+       int i;
+       socklen_t slen = sizeof(struct sockaddr_in);
+       char buf[BUF_SIZE];
+       int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+       if (s == -1) {
+               perror("socket");
+               exit(1);
+       }
+
+       prepare_address(AF_INET, PORT, &local_address);
+       local_address.sin_addr.s_addr = htonl(INADDR_ANY);
+       if (bind(s, (struct sockaddr *)(&local_address),
+               sizeof(struct sockaddr_in)) == -1) {
+               perror("bind");
+               exit(1);
+       }
+
+       for (i = 0; i < PACKET_NUMBER; i++) {
+               if (recvfrom(s, buf, BUF_SIZE, 0,
+                       (struct sockaddr *)&remote_address, &slen) == -1) {
+                       perror("recvfrom()");
+                       exit(1);
+               }
+               printf("Received packet from %s:%d\nData: %s\n\n",
+                       inet_ntoa(remote_address.sin_addr), ntohs(remote_address.sin_port), buf);
+       }
+
+       close(s);
+       return 0;
+}
diff --git a/src/vip-agent/vip-process.c b/src/vip-agent/vip-process.c
new file mode 100644 (file)
index 0000000..8686b0f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <Ecore.h>
+
+#include "const.h"
+#include "resourced.h"
+#include "trace.h"
+#include "proc-main.h"
+#include "cgroup.h"
+#include "proc-process.h"
+#include "macro.h"
+#include "config-parser.h"
+#include "file-helper.h"
+#include "module.h"
+#include "module-data.h"
+#include "vip-process.h"
+
+#define VIP_CONF_FILE          "/etc/resourced/vip-process.conf"
+#define VIP_CONF_SECTION       "VIP_PROCESS"
+#define VIP_CONF_NAME          "VIP_PROC_NAME"
+#define AGENT_PATH             "/usr/bin/vip-release-agent"
+#define VIP_RELEASE_AGENT      "/release_agent"
+#define VIP_NOTIFY_ON_RELEASE  "/notify_on_release"
+
+
+static int load_vip_config(struct parse_result *result, void *user_data)
+{
+       pid_t pid = 0;
+       char cgroup_name[MAX_NAME_LENGTH];
+       if (!result)
+               return -EINVAL;
+
+       if (strcmp(result->section, VIP_CONF_SECTION))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strcmp(result->name, VIP_CONF_NAME)) {
+               /* 1. find pid */
+               /* 2. decrease oom score adj for excepting it in oom candidate list */
+               /* 3. make cgroup */
+               pid =  find_pid_from_cmdline(result->value);
+               if (pid) {
+                       make_cgroup_subdir(VIP_CGROUP, result->value, NULL);
+                       snprintf(cgroup_name, sizeof(cgroup_name), "%s/%s",
+                                   VIP_CGROUP, result->value);
+                       cgroup_write_node(cgroup_name, TASK_FILE_NAME, pid);
+               }
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_vip_process_init(void *data)
+{
+       int checkfd;
+       checkfd = open(CHECK_RELEASE_PROGRESS, O_RDONLY, 0666);
+       if (checkfd >= 0)
+       {
+               if (unlink(CHECK_RELEASE_PROGRESS) < 0)
+                       _E("fail to remove %s file\n", CHECK_RELEASE_PROGRESS);
+               close(checkfd);
+       }
+       make_cgroup_subdir(DEFAULT_CGROUP, "vip", NULL);
+       mount_cgroup_subsystem("vip_cgroup", VIP_CGROUP, "none,name=vip_cgroup");
+       cgroup_write_node_str(VIP_CGROUP, VIP_RELEASE_AGENT, AGENT_PATH);
+       cgroup_write_node(VIP_CGROUP, VIP_NOTIFY_ON_RELEASE , 1);
+       config_parse(VIP_CONF_FILE, load_vip_config, NULL);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_vip_process_finalize(void *data)
+{
+       return RESOURCED_ERROR_NONE;
+}
+
+static struct module_ops vip_modules_ops = {
+       .priority = MODULE_PRIORITY_NORMAL,
+       .name = "vip-process",
+       .init = resourced_vip_process_init,
+       .exit = resourced_vip_process_finalize,
+};
+
+MODULE_REGISTER(&vip_modules_ops)
diff --git a/src/vip-agent/vip-process.conf b/src/vip-agent/vip-process.conf
new file mode 100644 (file)
index 0000000..b4c7572
--- /dev/null
@@ -0,0 +1,7 @@
+[VIP_PROCESS]
+# VIP process list
+VIP_PROC_NAME=Xorg
+VIP_PROC_NAME=enlightenment
+VIP_PROC_NAME=dbus-daemon
+VIP_PROC_NAME=amd
+VIP_PROC_NAME=sensord
similarity index 70%
rename from src/proc-stat/include/proc-winstate.h
rename to src/vip-agent/vip-process.h
index dd9d3ce..e47ad74 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  resourced
+ * resourced
  *
  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
  *
  */
 
 /**
- * @file proc_noti.h
- * @desc communication api with libresourced for grouping process
+ * @file proc-monitor.h
+ * @desc  proc monitor
  **/
 
-#ifndef __PROC_WINSTATE_H__
-#define __PROC_WINSTATE_H__
+#ifndef __RESOURCED_VIP_PROCESS_H__
+#define __RESOURCED_VIP_PROCESS_H__
 
-int proc_win_status_init(void);
-int proc_add_visibiliry(int pid);
+#define CHECK_RELEASE_PROGRESS "/tmp/.release_ongoing"
+#define VIP_CGROUP             "/sys/fs/cgroup/vip"
 
-#endif /*__PROC_WINSTATE_H__*/
+#endif /* __RESOURCED_VIP_PROCESS_H__ */
 
diff --git a/src/vip-agent/vip-release-agent.c b/src/vip-agent/vip-release-agent.c
new file mode 100644 (file)
index 0000000..22cfa91
--- /dev/null
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include "trace.h"
+#include "vip-process.h"
+
+#define TIZEN_DEBUG_MODE_FILE   "/opt/etc/.debugmode"
+#define DUMP_PATH "/usr/bin/all_log_dump.sh"
+#define REBOOT_PATH "/usr/sbin/reboot"
+
+static int check_debugenable(void)
+{
+       if (access(TIZEN_DEBUG_MODE_FILE, F_OK) == 0)
+               return 1;
+       else
+               return 0;
+}
+
+static int run_exec(char **argv)
+{
+       int status = 0;
+       pid_t pid = 0;
+
+       if (argv == NULL)
+               return -3;
+
+       pid = fork();
+
+       if (pid == -1)
+               return -1;
+
+       if (pid == 0) {
+               setpgid(0, 0);
+               if (execv(argv[0], argv) == -1) {
+                       _E("Error execv: %s.\n", strerror(errno));
+                       _exit(-1);
+               }
+               _exit(1);
+       }
+       do {
+               if (waitpid(pid, &status, 0) == -1) {
+                       if (errno != EINTR)
+                               return -1;
+               }
+               else {
+                       return status;
+               }
+       } while (1);
+}
+
+int main(int argc, char *argv[])
+{
+       int checkfd;
+       char *dumpargv[3] = {DUMP_PATH, NULL, NULL};
+       char *rebootargv[4] = {REBOOT_PATH, "silent", NULL, NULL};
+       DIR *dir = 0;
+
+       dir = opendir(VIP_CGROUP);
+       if (!dir) {
+               _E("doesn't support cgroup release agent");
+               return 0;
+       }
+       closedir(dir);
+
+       _E("call release agent : [%d:%s]\n", argc, argv[1]);
+
+       /* check previous process */
+       if (access(CHECK_RELEASE_PROGRESS, F_OK) == 0)
+               return 0;
+
+       /* make tmp file */
+       checkfd = creat(CHECK_RELEASE_PROGRESS, 0640);
+       if (checkfd < 0) {
+               _E("fail to make %s file\n", CHECK_RELEASE_PROGRESS);
+               checkfd = 0;
+       }
+
+       /* unmount cgroup for preventing launching another release-agent */
+       _E("systemd service stop");
+       umount2("/sys/fs/cgroup", MNT_FORCE |MNT_DETACH);
+
+       /* check debug level */
+       if (check_debugenable())
+               run_exec(dumpargv);
+
+       /* clear tmp file */
+       if (checkfd) {
+               if (unlink(CHECK_RELEASE_PROGRESS) < 0)
+                       _E("fail to remove %s file\n", CHECK_RELEASE_PROGRESS);
+               close(checkfd);
+       }
+
+       sync();
+
+       run_exec(rebootargv);
+       return 0;
+}
+
diff --git a/system-resource.manifest b/system-resource.manifest
new file mode 100644 (file)
index 0000000..3256181
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+<request>
+       <domain name="_"/>
+</request>
+</manifest>
index f0e2c91..a610592 100644 (file)
@@ -1,11 +1,16 @@
+# Package Information for pkg-config
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+# All rights reserved.
+#
+
 libdir=@LIBDIR@
 includedir=@INCLUDEDIR@
 
-Name: @PC_NAME@
+Name: @PC_NAME_DEPRECATED@
 Description: @PACKAGE_DESCRIPTION@
 Version: @VERSION@
 Requires: @PC_REQUIRED@
-#Libs: -L${libdir} @PC_PROVIDED_LIBS@
-Libs: -L${libdir} -lproc-stat
+Libs: -L${libdir} @PC_PROVIDED_LIBS@
 Cflags: @PC_CFLAGS@