diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | .gitreview | 5 | ||||
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | README.md | 26 | ||||
-rw-r--r-- | binding/CMakeLists.txt | 20 | ||||
-rw-r--r-- | binding/task-manager-binding.c | 179 | ||||
m--------- | conf.d/app-templates | 0 | ||||
-rwxr-xr-x | conf.d/autobuild/agl/autobuild | 67 | ||||
-rwxr-xr-x | conf.d/autobuild/linux/autobuild | 67 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 156 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 23 |
12 files changed, 551 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build
\ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e07cae1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "conf.d/app-templates"] + path = conf.d/app-templates + url = https://gerrit.automotivelinux.org/gerrit/p/apps/app-templates.git diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..2fbb6e1 --- /dev/null +++ b/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=gerrit.automotivelinux.org +port=29418 +project=apps/agl-service-taskmanager +defaultbranch=master diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fdecd32 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.3) + +include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..113a38e --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +##AGL-task-manager + +Task Manager service queries the system folder /proc to collect data on +the processes currently running on the machine. Information such as +process name, process ID, user, system CPU usage, user CPU usage, resident memory and state. + + +## Verbs + +| Name | Description | +|:-------------------|:------------------------------------------| +| get_process_list | retrieves the current processes from /proc| + + +## JSON response is an array of process entries each containing the values described below + +| Name | Description | +|:------------|-------------------------------------------------| +| cmd | name of each process | +| tid | unique process ID | +| euid | process user | +| scpu | % of CPU time used by process in kernel mode | +| ucpu | % of CPU time used by process in user time | +| resident_mem| amount of resident memory used | +| state | state of process | + diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt new file mode 100644 index 0000000..b1dfac9 --- /dev/null +++ b/binding/CMakeLists.txt @@ -0,0 +1,20 @@ +# Add target to project dependency list +PROJECT_TARGET_ADD(taskmanager) + + # Define project Targets + file(GLOB sourcelist "*.c") + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} MODULE ${sourcelist}) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "afb-" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + TARGET_LINK_LIBRARIES(${TARGET_NAME} + ${link_libraries} + ) diff --git a/binding/task-manager-binding.c b/binding/task-manager-binding.c new file mode 100644 index 0000000..43c9ee3 --- /dev/null +++ b/binding/task-manager-binding.c @@ -0,0 +1,179 @@ +#include <proc/readproc.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <proc/sysinfo.h> +#include <math.h> +#include <unistd.h> +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> + +void get_process_list(struct afb_req request); +struct pstat* fill_pstat(proc_t *proc_info); +struct cpu_percentage* cpu_calculate(struct pstat*, struct pstat*); +struct process_container* process_container_constr(char* process_name, int euid, struct pstat *pstat_values); +static const struct afb_binding_interface *interface; +static struct afb_event event; + +struct pstat { + long long unsigned int utime_ticks; + long long unsigned int cutime_ticks; + long long unsigned int stime_ticks; + long long unsigned int cstime_ticks; + long unsigned int cpu_total_time; +}; + +struct cpu_percentage { + double ucpu_usage; + double scpu_usage; +}; + +struct process_container { + char *process_name; + // int tid; + int euid; + struct pstat *pstat_values; +}; + +void get_process_list(struct afb_req request){ + + int seconds = 1, page_size; + page_size = getpagesize(); + struct pstat *last_pstat_values, *now_pstat_values; + struct cpu_percentage *cpu_usage; + struct process_container *process_obj, *elem = NULL; + struct process_container* object_container[65535]; // array holding process objects + struct json_object *ret_json, *json_array, *json_obj; + ret_json = json_object_new_object(); + json_array = json_object_new_array(); + char state_str[2] = "\0"; + + PROCTAB* proc = openproc(PROC_FILLMEM | PROC_FILLSTAT); + if (!proc){ + AFB_REQ_ERROR(request, "Unable to open /proc!"); + afb_req_fail_f(request, "Failed", "Error processing arguments."); + } + + proc_t* proc_info; + while ((proc_info = readproc(proc, NULL)) != NULL) { + last_pstat_values = fill_pstat(proc_info); + process_obj = process_container_constr(proc_info->cmd, proc_info->euid, last_pstat_values); + object_container[proc_info->tid] = process_obj; + freeproc(proc_info); + } + + sleep(seconds); + + proc = openproc(PROC_FILLMEM | PROC_FILLSTAT); + if (!proc){ + AFB_REQ_ERROR(request, "Unable to open /proc!"); + afb_req_fail_f(request, "Failed", "Error processing arguments."); + } + + proc_t* proc_info2; + while ((proc_info2 = readproc(proc, NULL)) != NULL) { + now_pstat_values = fill_pstat(proc_info2); + elem = object_container[proc_info2->tid]; + if(elem){ + cpu_usage = cpu_calculate(elem->pstat_values, now_pstat_values); + json_obj = json_object_new_object(); + json_object_object_add(json_obj, "cmd", json_object_new_string(proc_info2->cmd)); + json_object_object_add(json_obj, "tid", json_object_new_int(proc_info2->tid)); + json_object_object_add(json_obj, "euid", json_object_new_int(proc_info2->euid)); + json_object_object_add(json_obj, "scpu", json_object_new_double(cpu_usage->scpu_usage)); + json_object_object_add(json_obj, "ucpu", json_object_new_double(cpu_usage->ucpu_usage)); + json_object_object_add(json_obj, "resident_mem", json_object_new_double((proc_info2->resident * page_size)/ pow(1024, 2))); + state_str[0] = proc_info2->state; + json_object_object_add(json_obj, "state", json_object_new_string(state_str)); + json_object_array_add(json_array, json_obj); + } + freeproc(proc_info2); + } + json_object_object_add(ret_json, "processes", json_array); + afb_req_success(request, ret_json, NULL); + + closeproc(proc); + // printf ("The json object created: %s\n", json_object_to_json_string(ret_json)); +} + +struct pstat* fill_pstat(proc_t *proc_info){ + + long unsigned int cpu_total_time; + long unsigned int cpu_time[10]; + struct pstat *pstat_values = malloc(sizeof(struct pstat)); + + pstat_values->utime_ticks = proc_info->utime; + pstat_values->cutime_ticks = proc_info->cutime; + pstat_values->stime_ticks = proc_info->stime; + pstat_values->cstime_ticks = proc_info->cstime; + + FILE *fstat = fopen("/proc/stat", "r"); + if (fstat == NULL) { + perror("FOPEN ERROR "); + fclose(fstat); + } + + memset(cpu_time, 0, sizeof(cpu_time)); + if (fscanf(fstat, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3], + &cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7], + &cpu_time[8], &cpu_time[9]) == EOF) { + fclose(fstat); + } + + fclose(fstat); + + /* + * Returns total CPU time. It is a sum of user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice + */ + for(int i = 0; i < 10; i++) + pstat_values->cpu_total_time += cpu_time[i]; + + return pstat_values; +} + +struct cpu_percentage* cpu_calculate(struct pstat *last_pstat_values, struct pstat *now_pstat_values){ + + long unsigned int total_time_diff = now_pstat_values->cpu_total_time - last_pstat_values->cpu_total_time; + + struct cpu_percentage *cpu_values = malloc(sizeof(struct cpu_percentage)); + + cpu_values->ucpu_usage = 100 * (((now_pstat_values->utime_ticks + now_pstat_values->cutime_ticks) + - (last_pstat_values->utime_ticks + last_pstat_values->cutime_ticks)) / (double) total_time_diff); + + cpu_values->scpu_usage = 100 * (((now_pstat_values->stime_ticks + now_pstat_values->cstime_ticks) + - (last_pstat_values->stime_ticks + last_pstat_values->cstime_ticks)) / (double) total_time_diff); + + return cpu_values; +} + +struct process_container* process_container_constr(char* process_name, int euid, struct pstat *pstat_values) { + + struct process_container *r = malloc(sizeof(struct process_container)); + r->process_name = process_name; + r->euid = euid; + r->pstat_values = pstat_values; + + return r; +} + +static const struct afb_verb_v2 _afb_verbs_v2_taskmanager[] = { + { + .verb = "get_process_list", + .callback = get_process_list, + .auth = NULL, + .info = "Get an array of all processes currently running on the system", + .session = AFB_SESSION_NONE_V2 + } +}; + + +const struct afb_binding_v2 afbBindingV2 = { + .api = "taskmanager", + .specification = NULL, + .info = "Task Manager service", + .verbs = _afb_verbs_v2_taskmanager, + .noconcurrency = 0 +};
\ No newline at end of file diff --git a/conf.d/app-templates b/conf.d/app-templates new file mode 160000 +Subproject e841a7787b2315f068f50d77b04196b7d7ccc17 diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/agl/autobuild @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# Copyright (C) 2015, 2016 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/autobuild/linux/autobuild b/conf.d/autobuild/linux/autobuild new file mode 100755 index 0000000..83097ab --- /dev/null +++ b/conf.d/autobuild/linux/autobuild @@ -0,0 +1,67 @@ +#!/usr/bin/make -f +# Copyright (C) 2015, 2016 "IoT.bzh" +# Author "Romain Forlot" <romain.forlot@iot.bzh> +# +# 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. + +THISFILE := $(lastword $(MAKEFILE_LIST)) +BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build) +DEST := ${BUILD_DIR}/target + +.PHONY: all clean distclean configure build package help update + +all: help + +help: + @echo "List of targets available:" + @echo "" + @echo "- all" + @echo "- clean" + @echo "- distclean" + @echo "- configure" + @echo "- build: compilation, link and prepare files for package into a widget" + @echo "- package: output a widget file '*.wgt'" + @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory" + @echo "" + @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt" + @echo "Don't use your build dir as DEST as wgt file is generated at this location" + +update: configure + @cmake --build ${BUILD_DIR} --target autobuild + +clean: + @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean + +distclean: + @rm -rf ${BUILD_DIR} + +configure: ${BUILD_DIR}/Makefile + +build: configure + @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all + +package: build + @mkdir -p ${BUILD_DIR}/$@/bin + @mkdir -p ${BUILD_DIR}/$@/etc + @mkdir -p ${BUILD_DIR}/$@/lib + @mkdir -p ${BUILD_DIR}/$@/htdocs + @mkdir -p ${BUILD_DIR}/$@/var + @cmake --build ${BUILD_DIR} --target widget + @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST} + +install: build + @cmake --build ${BUILD_DIR} --target install + +${BUILD_DIR}/Makefile: + @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR} + @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake new file mode 100644 index 0000000..500a4b9 --- /dev/null +++ b/conf.d/cmake/config.cmake @@ -0,0 +1,156 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll <fulup@iot.bzh> +# +# 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. +########################################################################### + +# Project Info +# ------------------ +set(PROJECT_NAME agl-service-taskmanager) +set(PROJECT_PRETTY_NAME "Task Manager") +set(PROJECT_DESCRIPTION "Display resource information on running tasks") +set(PROJECT_URL "https://git.automotivelinux.org/apps/agl-service-taskmanager") +set(PROJECT_ICON "icon.png") +set(PROJECT_AUTHOR "Dimitrov,Yordan") +set(PROJECT_AUTHOR_MAIL "y.dimitrov.14@gmail.com") +set(PROJECT_LICENSE "APL2.0") +set(PROJECT_LANGUAGES "C") + +# Where are stored default templates files from submodule or subtree app-templates in your project tree +# relative to the root project directory +set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates") + +# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain +# but used and must be built and linked. +# set(PROJECT_LIBDIR "libs") + +# Which directories inspect to find CMakeLists.txt target files +# set(PROJECT_SRC_DIR_PATTERN "*") + +# Compilation Mode (DEBUG, RELEASE) +# ---------------------------------- +#set(BUILD_TYPE "DEBUG") +#set(USE_EFENCE 1) + +# Kernel selection if needed. You can choose between a +# mandatory version to impose a minimal version. +# Or check Kernel minimal version and just print a Warning +# about missing features and define a preprocessor variable +# to be used as preprocessor condition in code to disable +# incompatibles features. Preprocessor define is named +# KERNEL_MINIMAL_VERSION_OK. +# +# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and +# Yocto SDK Kernel version. +# ----------------------------------------------- +#set (kernel_mandatory_version 4.8) +#set (kernel_minimal_version 4.8) + +# Compiler selection if needed. Impose a minimal version. +# ----------------------------------------------- +set (gcc_minimal_version 4.9) + +# PKG_CONFIG required packages +# ----------------------------- +set (PKG_REQUIRED_LIST + json-c + libprocps + afb-daemon +) + +# You can also consider to include libsystemd +# ----------------------------------- +#list (APPEND PKG_REQUIRED_LIST libsystemd>=222) + +# Prefix path where will be installed the files +# Default: /usr/local (need root permission to write in) +# ------------------------------------------------------ +#set(INSTALL_PREFIX /opt/AGL CACHE PATH "INSTALL PREFIX PATH") + +# Customize link option +# ----------------------------- +#list(APPEND link_libraries -an-option) + +# Optional location for config.xml.in +# ----------------------------------- +#set(WIDGET_ICON "\"conf.d/wgt/${PROJECT_ICON}\"" CACHE PATH "Path to the widget icon") +set(WIDGET_CONFIG_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in" CACHE PATH "Path to widget config file template (config.xml.in)") + +# Mandatory widget Mimetype specification of the main unit +# -------------------------------------------------------------------------- +# Choose between : +#- text/html : HTML application, +# content.src designates the home page of the application +# +#- application/vnd.agl.native : AGL compatible native, +# content.src designates the relative path of the binary. +# +# - application/vnd.agl.service: AGL service, content.src is not used. +# +#- ***application/x-executable***: Native application, +# content.src designates the relative path of the binary. +# For such application, only security setup is made. +# +set(WIDGET_TYPE application/vnd.agl.service) + +# Mandatory Widget entry point file of the main unit +# -------------------------------------------------------------- +# This is the file that will be executed, loaded, +# at launch time by the application framework. +# +set(WIDGET_ENTRY_POINT lib/afb-taskmanager.so) + +# Optional dependencies order +# --------------------------- +#set(EXTRA_DEPENDENCIES_ORDER) + +# Optional Extra global include path +# ----------------------------------- +#set(EXTRA_INCLUDE_DIRS) + +# Optional extra libraries +# ------------------------- +#set(EXTRA_LINK_LIBRARIES) + +# Optional force binding Linking flag +# ------------------------------------ +# set(BINDINGS_LINK_FLAG LinkOptions ) + +# Optional force package prefix generation, like widget +# ----------------------------------------------------- +# set(PKG_PREFIX DestinationPath) + +# Optional Application Framework security token +# and port use for remote debugging. +#------------------------------------------------------------ +set(AFB_TOKEN "" CACHE PATH "Default binder security token") +set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port") + +# Print a helper message when every thing is finished +# ---------------------------------------------------- +set(CLOSING_MESSAGE "Typical binding launch: cd ${CMAKE_BINARY_DIR}/package \\&\\& afb-daemon --port=${AFB_REMPORT} --workdir=. --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose") +set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") + +# Optional schema validator about now only XML, LUA and JSON +# are supported +#------------------------------------------------------------ +#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler") +#set(XML_CHECKER "xmllint" CACHE STRING "XML linter") +#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter") + +# This include is mandatory and MUST happens at the end +# of this file, else you expose you to unexpected behavior +# ----------------------------------------------------------- +include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake) diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in new file mode 100644 index 0000000..dca8bd7 --- /dev/null +++ b/conf.d/wgt/config.xml.in @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@"> + <name>@PROJECT_NAME@</name> + <icon src="@PROJECT_ICON@"/> + <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/> + <description>@PROJECT_DESCRIPTION@</description> + <author>@PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@></author> + <license>@PROJECT_LICENSE@</license> + + <feature name="urn:AGL:widget:required-permission"> + <param name="urn:AGL:permission::public:hidden" value="required" /> + <param name="urn:AGL:permission::system:run-by-default" value="required" /> + <param name="urn:AGL:permission::public:no-htdocs" value="required" /> + </feature> + + <feature name="urn:AGL:widget:provided-api"> + <param name="taskmanager" value="ws" /> + </feature> + + <feature name="urn:AGL:widget:required-api"> + <param name="@WIDGET_ENTRY_POINT@" value="local" /> + </feature> +</widget> |