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