Separate debug log with info config
[platform/core/connectivity/stc-manager.git] / plugin / procfs / stc-plugin-procfs.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdbool.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/connector.h>
27 #include <linux/cn_proc.h>
28 #include <glib.h>
29
30 #include "stc-plugin-procfs.h"
31 #include "stc-monitor.h"
32 #include "helper-net-cls.h"
33 #include "helper-procfs.h"
34
35 //LCOV_EXCL_START
36 typedef struct {
37         pid_t pid;
38 } proc_key_s;
39
40 typedef struct {
41         char cmdline[PROC_NAME_MAX];
42         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
43 } proc_value_s;
44
45 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
46         struct nlmsghdr nl_hdr;
47         struct __attribute__ ((__packed__)) {
48                 struct cn_msg cn_msg;
49                 enum proc_cn_mcast_op cn_mcast;
50         };
51 } nl_connector_msg_s;
52
53 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
54         struct nlmsghdr nl_hdr;
55         struct __attribute__ ((__packed__)) {
56                 struct cn_msg cn_msg;
57                 struct proc_event proc_ev;
58         };
59 } nl_connector_proc_event_s;
60
61 static int nl_connector_sock = -1;
62 static guint nl_connector_gsource_id = 0;
63 static GTree *proc_tree;
64
65 static gboolean __process_nl_connector_message(GIOChannel *source,
66                                                GIOCondition condition,
67                                                gpointer user_data);
68
69 static int __proc_tree_key_compare(gconstpointer a, gconstpointer b,
70                                    gpointer UNUSED user_data)
71 {
72         proc_key_s *key_a = (proc_key_s *)a;
73         proc_key_s *key_b = (proc_key_s *)b;
74
75         return key_a->pid - key_b->pid;
76 }
77
78 static void __proc_tree_value_free(gpointer data)
79 {
80         proc_value_s *value = (proc_value_s *)data;
81
82         FREE(value);
83 }
84
85 static void __proc_tree_key_free(gpointer data)
86 {
87         proc_key_s *key = (proc_key_s *)data;
88
89         FREE(key);
90 }
91
92 static proc_value_s * __proc_tree_lookup(const proc_key_s *key)
93 {
94         proc_value_s *lookup;
95
96         if (proc_tree == NULL) {
97                 STC_LOGE("tree is null");
98                 return NULL;
99         }
100
101         lookup = g_tree_lookup(proc_tree, key);
102         return lookup;
103 }
104
105 /*
106 static gboolean __proc_tree_foreach_print(gpointer key, gpointer value,
107                                           gpointer data)
108 {
109         proc_key_s *proc_key = (proc_key_s *)key;
110         proc_value_s *proc_value = (proc_value_s *)value;
111
112         STC_LOGD("Proc pid [\033[1;33m%d\033[0;m] ppid [%s] "
113                 "cmdline [\033[0;34m%s\033[0;m]", proc_key->pid,
114                 proc_value->status[PROC_STATUS_PPID], proc_value->cmdline);
115
116         return FALSE;
117 }
118
119 static void __proc_tree_printall(void)
120 {
121         g_tree_foreach(proc_tree, __proc_tree_foreach_print, NULL);
122 }
123 */
124
125 static proc_value_s * __proc_tree_find_parent(proc_value_s *value)
126 {
127         proc_value_s *parent = NULL;
128         proc_value_s *lookup = value;
129
130         do {
131                 proc_key_s key;
132                 key.pid = atoi(lookup->status[PROC_STATUS_PPID]);
133                 lookup = __proc_tree_lookup(&key);
134                 if (lookup != NULL)
135                         parent = lookup;
136         } while (lookup);
137
138         if (STC_DEBUG_LOG && STC_STAT_LOG) {
139                 if (parent != NULL)
140                         STC_LOGD("\033[0;35mPARENT\033[0;m: tgid[\033[1;33m%s\033[0;m] "
141                                 "pid[%s] ppid[%s] cmdline[\033[0;34m%s\033[0;m] name[%s]",
142                                 parent->status[PROC_STATUS_TGID], parent->status[PROC_STATUS_PID],
143                                 parent->status[PROC_STATUS_PPID], parent->cmdline,
144                                 parent->status[PROC_STATUS_NAME]);
145         }
146
147         return parent;
148 }
149
150 static void __proc_tree_add(proc_key_s *key, proc_value_s *value)
151 {
152         proc_value_s *lookup;
153         proc_value_s *parent;
154
155         if (proc_tree == NULL) {
156                 STC_LOGE("tree is null");
157                 return;
158         }
159
160         if (key == NULL || value == NULL) {
161                 if (STC_DEBUG_LOG && STC_STAT_LOG)
162                         STC_LOGE("invalid parameters");
163                 return;
164         }
165
166         lookup = g_tree_lookup(proc_tree, key);
167         if (lookup)
168                 return;
169
170         proc_key_s *proc_key = MALLOC0(proc_key_s, 1);
171         if (proc_key == NULL) {
172                 STC_LOGE("memory allocation failed");
173                 return;
174         }
175
176         proc_value_s *proc_value = MALLOC0(proc_value_s, 1);
177         if (proc_value == NULL) {
178                 STC_LOGE("memory allocation failed");
179                 FREE(proc_key);
180                 return;
181         }
182
183         memcpy(proc_key, key, sizeof(proc_key_s));
184         memcpy(proc_value, value, sizeof(proc_value_s));
185
186         g_tree_insert(proc_tree, proc_key, proc_value);
187
188         /*
189         __proc_tree_printall();
190         */
191
192         parent = __proc_tree_find_parent(proc_value);
193         if (parent != NULL)
194                 stc_plugin_procfs_status_changed(STC_CMD_SET_SERVICE_LAUNCHED, proc_key->pid,
195                         parent->cmdline, parent->cmdline, STC_APP_TYPE_SERVICE);
196         else
197                 stc_plugin_procfs_status_changed(STC_CMD_SET_SERVICE_LAUNCHED, proc_key->pid,
198                         proc_value->cmdline, proc_value->cmdline, STC_APP_TYPE_SERVICE);
199 }
200
201 static void __proc_tree_remove(const proc_key_s *key,
202                                                 const proc_value_s *value)
203 {
204         if (proc_tree == NULL) {
205                 STC_LOGE("tree is null");
206                 return;
207         }
208
209         stc_plugin_procfs_status_changed(STC_CMD_SET_TERMINATED, key->pid,
210                         value->cmdline, value->cmdline, STC_APP_TYPE_NONE);
211
212         g_tree_remove(proc_tree, key);
213
214         /*
215         __proc_tree_printall();
216         */
217 }
218
219 static gboolean __check_excn(char *cmdline)
220 {
221         stc_error_e ret = STC_ERROR_NONE;
222
223         if (cmdline[0] == '(')
224                 return TRUE;
225
226         ret = stc_monitor_check_excn_by_cmdline(cmdline);
227         if (ret == STC_ERROR_UNINITIALIZED ||
228                 ret == STC_ERROR_NO_DATA)
229                 return FALSE;
230         else
231                 return TRUE;
232 }
233
234 static void __open_nl_connector_sock(void)
235 {
236         __STC_LOG_FUNC_ENTER__;
237         GIOChannel *gio = NULL;
238
239         if (nl_connector_sock != -1 &&
240             nl_connector_gsource_id != 0) {
241                 STC_LOGE("Socket is already open");
242                 __STC_LOG_FUNC_EXIT__;
243                 return;
244         }
245
246         if (nl_connector_sock != -1) {
247                 close(nl_connector_sock);
248                 nl_connector_sock = -1;
249         }
250
251         if (nl_connector_gsource_id != 0) {
252                 g_source_remove(nl_connector_gsource_id);
253                 nl_connector_gsource_id = 0;
254         }
255
256         nl_connector_sock = create_netlink(NETLINK_CONNECTOR, CN_IDX_PROC);
257         if (nl_connector_sock == -1) {
258                 __STC_LOG_FUNC_EXIT__;
259                 return;
260         }
261
262         gio = g_io_channel_unix_new(nl_connector_sock);
263         nl_connector_gsource_id =
264                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
265                                (GIOFunc) __process_nl_connector_message,
266                                NULL);
267         g_io_channel_unref(gio);
268         __STC_LOG_FUNC_EXIT__;
269 }
270
271 static void __close_nl_connector_sock(void)
272 {
273         __STC_LOG_FUNC_ENTER__;
274         if (nl_connector_sock != -1) {
275                 close(nl_connector_sock);
276                 nl_connector_sock = -1;
277         }
278
279         if (nl_connector_gsource_id != 0) {
280                 g_source_remove(nl_connector_gsource_id);
281                 nl_connector_gsource_id = 0;
282         }
283         __STC_LOG_FUNC_EXIT__;
284 }
285
286 static void __reopen_nl_connector_sock(void)
287 {
288         __close_nl_connector_sock();
289         __open_nl_connector_sock();
290 }
291
292 static void __process_event_fork(int tgid, int pid)
293 {
294         char cmdline[PROC_NAME_MAX] = {0, };
295         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
296
297         /* TODO: Add newly created thread to the process tasks */
298         if (tgid != pid)
299                 return;
300
301         memset(status, 0x0, sizeof(status));
302
303         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
304             STC_ERROR_NONE == proc_get_status(pid, status)) {
305
306                 if (__check_excn(cmdline))
307                         return;
308
309                 unsigned int i;
310                 proc_key_s key;
311                 proc_value_s value;
312
313                 memset(&key, 0x0, sizeof(proc_key_s));
314                 memset(&value, 0x0, sizeof(proc_value_s));
315
316                 key.pid = tgid;
317                 for (i = 0; i < PROC_STATUS_CNT; ++i)
318                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
319                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
320
321                 if (STC_DEBUG_LOG && STC_STAT_LOG)
322                         STC_LOGD("\033[1;32mFORK\033[0;m: tgid[\033[1;33m%d\033[0;m] "
323                         "ppid=[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
324                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
325
326                 __proc_tree_add(&key, &value);
327         }
328 }
329
330 static void __process_event_exec(int tgid, int pid)
331 {
332         char cmdline[PROC_NAME_MAX] = {0, };
333         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
334
335         /* TODO: Add newly created thread to the process tasks */
336         if (tgid != pid)
337                 return;
338
339         memset(status, 0x0, sizeof(status));
340
341         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
342             STC_ERROR_NONE == proc_get_status(pid, status)) {
343
344                 if (__check_excn(cmdline))
345                         return;
346
347                 unsigned int i;
348                 proc_key_s key;
349                 proc_value_s value;
350
351                 memset(&key, 0x0, sizeof(proc_key_s));
352                 memset(&value, 0x0, sizeof(proc_value_s));
353
354                 key.pid = tgid;
355                 for (i = 0; i < PROC_STATUS_CNT; ++i)
356                         g_strlcpy(value.status[i], status[i],
357                                   sizeof(value.status[i]));
358                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
359
360                 if (STC_DEBUG_LOG && STC_STAT_LOG)
361                         STC_LOGD("\033[1;32mEXEC\033[0;m: tgid[\033[1;33m%d\033[0;m] "
362                         "ppid[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
363                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
364
365                 __proc_tree_add(&key, &value);
366         }
367 }
368
369 static void __process_event_exit(int tgid, int pid, int exit_code)
370 {
371         proc_key_s key;
372         proc_value_s *lookup;
373
374         if (tgid != pid)
375                 return;
376
377         key.pid = tgid;
378         lookup = __proc_tree_lookup(&key);
379         if (lookup == NULL) /* unmonitored process */
380                 return;
381
382         if (STC_DEBUG_LOG && STC_STAT_LOG)
383                 STC_LOGD("\033[1;31mEXIT\033[0;m: tgid[\033[1;33m%d\033[0;m] "
384                         "cmdline[\033[0;34m%s\033[0;m] pid[%d] exitcode[%d]",
385                         tgid, lookup->cmdline, pid, exit_code);
386
387         __proc_tree_remove(&key, lookup);
388 }
389
390 static gboolean __process_nl_connector_message(GIOChannel *source,
391                                                GIOCondition condition,
392                                                gpointer user_data)
393 {
394         int ret;
395         int sock = g_io_channel_unix_get_fd(source);
396         nl_connector_proc_event_s msg;
397
398         if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
399             (condition & G_IO_NVAL)) {
400                 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
401
402                 STC_LOGE("Netlink Connector socket received G_IO event, closing"
403                          " socket. G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
404                          (condition & G_IO_ERR), (condition & G_IO_HUP),
405                          (condition & G_IO_NVAL));
406                 __reopen_nl_connector_sock();
407                 __STC_LOG_FUNC_EXIT__;
408                 return FALSE;
409         }
410
411         memset(&msg, 0, sizeof(nl_connector_proc_event_s));
412
413         ret = read(sock, &msg, sizeof(nl_connector_proc_event_s));
414         if (ret == 0) {
415                 __STC_LOG_FUNC_EXIT__;
416                 return TRUE;
417         }
418
419         switch (msg.proc_ev.what) {
420         case PROC_EVENT_FORK:
421                 __process_event_fork(msg.proc_ev.event_data.fork.child_tgid,
422                                      msg.proc_ev.event_data.fork.child_pid);
423                 break;
424         case PROC_EVENT_EXEC:
425                 __process_event_exec(msg.proc_ev.event_data.exec.process_tgid,
426                                      msg.proc_ev.event_data.exec.process_pid);
427                 break;
428         case PROC_EVENT_EXIT:
429                 __process_event_exit(msg.proc_ev.event_data.exit.process_tgid,
430                                      msg.proc_ev.event_data.exit.process_pid,
431                                      msg.proc_ev.event_data.exit.exit_code);
432                 break;
433         default:
434                 break;
435         }
436
437         return TRUE;
438 }
439
440 static int __subscribe_proc_events(void)
441 {
442         __STC_LOG_FUNC_ENTER__;
443         nl_connector_msg_s msg;
444         int ret;
445         int sock = nl_connector_sock;
446
447         if (sock == -1) {
448                 __STC_LOG_FUNC_EXIT__;
449                 return -1;
450         }
451
452         memset(&msg, 0, sizeof(nl_connector_msg_s));
453
454         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
455         msg.nl_hdr.nlmsg_pid = getpid();
456         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
457
458         msg.cn_msg.id.idx = CN_IDX_PROC;
459         msg.cn_msg.id.val = CN_VAL_PROC;
460         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
461
462         msg.cn_mcast = PROC_CN_MCAST_LISTEN;
463
464         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
465         if (ret == -1) {
466                 STC_LOGE("Error sending netlink connector message");
467                 __STC_LOG_FUNC_EXIT__;
468                 return -1;
469         }
470
471         __STC_LOG_FUNC_EXIT__;
472         return 0;
473 }
474
475 static int __unsubscribe_proc_events(void)
476 {
477         __STC_LOG_FUNC_ENTER__;
478         nl_connector_msg_s msg;
479         int ret;
480         int sock = nl_connector_sock;
481
482         if (sock == -1) {
483                 __STC_LOG_FUNC_EXIT__;
484                 return -1;
485         }
486
487         memset(&msg, 0, sizeof(nl_connector_msg_s));
488
489         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
490         msg.nl_hdr.nlmsg_pid = getpid();
491         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
492
493         msg.cn_msg.id.idx = CN_IDX_PROC;
494         msg.cn_msg.id.val = CN_VAL_PROC;
495         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
496
497         msg.cn_mcast = PROC_CN_MCAST_IGNORE;
498
499         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
500         if (ret == -1) {
501                 STC_LOGE("Error sending netlink connector message");
502                 __STC_LOG_FUNC_EXIT__;
503                 return -1;
504         }
505
506         __STC_LOG_FUNC_EXIT__;
507         return 0;
508 }
509
510 static bool __process_pid_cb(pid_t pid, void *user_data)
511 {
512         char cmdline[PROC_NAME_MAX] = {0, };
513         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
514
515         memset(status, 0x0, sizeof(status));
516
517         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
518             STC_ERROR_NONE == proc_get_status(pid, status)) {
519
520                 if (__check_excn(cmdline))
521                         return true;
522
523                 unsigned int i;
524                 proc_key_s key;
525                 proc_value_s value;
526
527                 memset(&key, 0x0, sizeof(proc_key_s));
528                 memset(&value, 0x0, sizeof(proc_value_s));
529
530                 key.pid = pid;
531                 for (i = 0; i < PROC_STATUS_CNT; ++i)
532                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
533                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
534
535                 __proc_tree_add(&key, &value);
536         }
537
538         return true;
539 }
540
541 int stc_plugin_procfs_initialize(void)
542 {
543         __STC_LOG_FUNC_ENTER__;
544
545         proc_tree = g_tree_new_full(__proc_tree_key_compare, NULL,
546                                     __proc_tree_key_free,
547                                     __proc_tree_value_free);
548
549         /* TODO: Fill proc tree with current procfs state */
550
551         __open_nl_connector_sock();
552         __subscribe_proc_events();
553         __STC_LOG_FUNC_EXIT__;
554         return STC_ERROR_NONE;
555 }
556
557 int stc_plugin_procfs_deinitialize(void)
558 {
559         __STC_LOG_FUNC_ENTER__;
560
561         if (nl_connector_sock == -1) {
562                 STC_LOGD("socket already closed");
563                 return STC_ERROR_NONE;
564         }
565
566         __unsubscribe_proc_events();
567         __close_nl_connector_sock();
568
569         g_tree_destroy(proc_tree);
570         proc_tree = NULL;
571
572         __STC_LOG_FUNC_EXIT__;
573         return STC_ERROR_NONE;
574 }
575
576 stc_error_e stc_plugin_procfs_load(void)
577 {
578         __STC_LOG_FUNC_ENTER__;
579
580         proc_foreach_pid(__process_pid_cb, NULL);
581
582         __STC_LOG_FUNC_EXIT__;
583         return STC_ERROR_NONE;
584 }
585
586 stc_error_e stc_plugin_procfs_status_changed(stc_cmd_type_e cmd,
587                                                 pid_t pid,
588                                                 const gchar *app_id,
589                                                 const gchar *pkg_id,
590                                                 stc_app_type_e app_type)
591 {
592         stc_error_e ret = STC_ERROR_NONE;
593
594         if ((pkg_id && app_id) && STC_DEBUG_LOG && STC_STAT_LOG)
595                 STC_LOGD("cmd[%d] pkgid[%s] appid[%s] pid[%d] type[%d]",
596                         cmd, pkg_id, app_id, pid, app_type);
597
598         switch (cmd) {
599         case STC_CMD_SET_FOREGRD:
600         {
601                 uint32_t fg_classid;
602                 uint32_t bg_classid;
603                 char *bg_app_id;
604                 stc_app_value_s app_value;
605                 stc_proc_value_s proc_value;
606
607                 memset(&app_value, 0, sizeof(stc_app_value_s));
608                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
609
610                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
611
612                 app_value.type = app_type;
613                 app_value.state = STC_APP_STATE_FOREGROUND;
614                 app_value.processes = NULL;
615
616                 proc_value.pid = pid;
617                 proc_value.ground = STC_APP_STATE_FOREGROUND;
618
619                 bg_classid = get_classid_by_app_id(bg_app_id, FALSE);
620                 fg_classid = get_classid_by_app_id(app_id, TRUE);
621
622                 stc_monitor_app_add(fg_classid, app_id, pkg_id, app_value);
623
624                 stc_monitor_proc_move(bg_classid, fg_classid);
625
626                 stc_monitor_proc_add(fg_classid, app_id, proc_value);
627                 stc_monitor_proc_update_ground(fg_classid, app_id, proc_value);
628
629                 FREE(bg_app_id);
630                 break;
631         }
632         case STC_CMD_SET_BACKGRD:
633         {
634                 uint32_t bg_classid;
635                 uint32_t fg_classid;
636                 char *bg_app_id;
637                 stc_app_value_s app_value;
638                 stc_proc_value_s proc_value;
639
640                 memset(&app_value, 0, sizeof(stc_app_value_s));
641                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
642
643                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
644
645                 app_value.type = app_type;
646                 app_value.state = STC_APP_STATE_BACKGROUND;
647                 app_value.processes = NULL;
648
649                 proc_value.pid = pid;
650                 proc_value.ground = STC_APP_STATE_BACKGROUND;
651
652                 fg_classid = get_classid_by_app_id(app_id, FALSE);
653                 bg_classid = get_classid_by_app_id(bg_app_id, TRUE);
654
655                 stc_monitor_app_add(bg_classid, bg_app_id, pkg_id, app_value);
656
657                 stc_monitor_proc_move(fg_classid, bg_classid);
658
659                 stc_monitor_proc_add(bg_classid, bg_app_id, proc_value);
660                 stc_monitor_proc_update_ground(bg_classid, bg_app_id, proc_value);
661
662                 FREE(bg_app_id);
663                 break;
664         }
665         case STC_CMD_SET_SERVICE_LAUNCHED:
666         {
667                 uint32_t classid;
668                 char *bg_app_id;
669                 stc_app_value_s app_value;
670                 stc_proc_value_s proc_value;
671                 gboolean is_exist;
672
673                 memset(&app_value, 0, sizeof(stc_app_value_s));
674                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
675
676                 classid = get_classid_by_app_id(app_id, FALSE);
677                 is_exist = stc_monitor_app_lookup(classid);
678                 if (is_exist) {
679                         app_value.type = app_type;
680                         app_value.state = STC_APP_STATE_FOREGROUND;
681                         app_value.processes = NULL;
682
683                         proc_value.pid = pid;
684                         proc_value.ground = STC_APP_STATE_FOREGROUND;
685
686                         stc_monitor_app_add(classid, app_id, pkg_id, app_value);
687                         stc_monitor_proc_add(classid, app_id, proc_value);
688                 } else {
689                         bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
690                         classid = get_classid_by_app_id(bg_app_id, TRUE);
691
692                         app_value.type = app_type;
693                         app_value.state = STC_APP_STATE_BACKGROUND;
694                         app_value.processes = NULL;
695
696                         proc_value.pid = pid;
697                         proc_value.ground = STC_APP_STATE_BACKGROUND;
698
699                         stc_monitor_app_add(classid, bg_app_id, pkg_id, app_value);
700                         stc_monitor_proc_add(classid, bg_app_id, proc_value);
701
702                         FREE(bg_app_id);
703                 }
704                 break;
705         }
706         case STC_CMD_SET_TERMINATED:
707         {
708                 uint32_t classid;
709                 char *bg_app_id;
710
711                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
712                 classid = get_classid_by_app_id(bg_app_id, FALSE);
713
714                 if (classid == STC_UNKNOWN_CLASSID)
715                         classid = get_classid_by_app_id(app_id, FALSE);
716
717                 stc_monitor_proc_remove(classid, pid);
718
719                 FREE(bg_app_id);
720                 break;
721         }
722         default:
723                 STC_LOGE("Unhandled command");
724                 ret = STC_ERROR_INVALID_PARAMETER;
725         }
726
727         return ret;
728 }
729
730 API stc_plugin_procfs_s stc_plugin_procfs = {
731         .initialize_plugin =
732                 stc_plugin_procfs_initialize,
733         .deinitialize_plugin =
734                 stc_plugin_procfs_deinitialize,
735         .procfs_load =
736                 stc_plugin_procfs_load,
737         .procfs_status_changed =
738                 stc_plugin_procfs_status_changed
739 };
740 //LCOV_EXCL_STOP