Refactoring structures for monitoring and restrictions
[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
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_DEBUG_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_DEBUG_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_monitor_check_excn_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                         if (STC_DEBUG_LOG)
309                                 STC_LOGD("[%s] monitoring is excepted", cmdline);
310                         return;
311                 }
312
313                 unsigned int i;
314                 proc_key_s key;
315                 proc_value_s value;
316
317                 memset(&key, 0x0, sizeof(proc_key_s));
318                 memset(&value, 0x0, sizeof(proc_value_s));
319
320                 key.pid = tgid;
321                 for (i = 0; i < PROC_STATUS_CNT; ++i)
322                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
323                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
324
325                 if (STC_DEBUG_LOG)
326                         STC_LOGD("\033[1;32mFORK\033[0;m: tgid[\033[1;33m%d\033[0;m] "
327                         "ppid=[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
328                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
329
330                 __proc_tree_add(&key, &value);
331         }
332 }
333
334 static void __process_event_exec(int tgid, int pid)
335 {
336         char cmdline[PROC_NAME_MAX] = {0, };
337         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
338
339         /* TODO: Add newly created thread to the process tasks */
340         if (tgid != pid)
341                 return;
342
343         memset(status, 0x0, sizeof(status));
344
345         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
346             STC_ERROR_NONE == proc_get_status(pid, status)) {
347
348                 if (__check_excn(cmdline)) {
349                         if (STC_DEBUG_LOG)
350                                 STC_LOGD("[%s] monitoring is excepted", cmdline);
351                         return;
352                 }
353
354                 unsigned int i;
355                 proc_key_s key;
356                 proc_value_s value;
357
358                 memset(&key, 0x0, sizeof(proc_key_s));
359                 memset(&value, 0x0, sizeof(proc_value_s));
360
361                 key.pid = tgid;
362                 for (i = 0; i < PROC_STATUS_CNT; ++i)
363                         g_strlcpy(value.status[i], status[i],
364                                   sizeof(value.status[i]));
365                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
366
367                 if (STC_DEBUG_LOG)
368                         STC_LOGD("\033[1;32mEXEC\033[0;m: tgid[\033[1;33m%d\033[0;m] "
369                         "ppid[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
370                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
371
372                 __proc_tree_add(&key, &value);
373         }
374 }
375
376 static void __process_event_exit(int tgid, int pid, int exit_code)
377 {
378         proc_key_s key;
379         proc_value_s *lookup;
380
381         if (tgid != pid)
382                 return;
383
384         key.pid = tgid;
385         lookup = __proc_tree_lookup(&key);
386         if (lookup == NULL) /* unmonitored process */
387                 return;
388
389         if (STC_DEBUG_LOG)
390                 STC_LOGD("\033[1;31mEXIT\033[0;m: tgid[\033[1;33m%d\033[0;m] "
391                         "cmdline[\033[0;34m%s\033[0;m] pid[%d] exitcode[%d]",
392                         tgid, lookup->cmdline, pid, exit_code);
393
394         __proc_tree_remove(&key, lookup);
395 }
396
397 static gboolean __process_nl_connector_message(GIOChannel *source,
398                                                GIOCondition condition,
399                                                gpointer user_data)
400 {
401         int ret;
402         int sock = g_io_channel_unix_get_fd(source);
403         nl_connector_proc_event_s msg;
404
405         if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
406             (condition & G_IO_NVAL)) {
407                 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
408
409                 STC_LOGE("Netlink Connector socket received G_IO event, closing"
410                          " socket. G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
411                          (condition & G_IO_ERR), (condition & G_IO_HUP),
412                          (condition & G_IO_NVAL));
413                 __reopen_nl_connector_sock();
414                 __STC_LOG_FUNC_EXIT__;
415                 return FALSE;
416         }
417
418         memset(&msg, 0, sizeof(nl_connector_proc_event_s));
419
420         ret = read(sock, &msg, sizeof(nl_connector_proc_event_s));
421         if (ret == 0) {
422                 __STC_LOG_FUNC_EXIT__;
423                 return TRUE;
424         }
425
426         switch (msg.proc_ev.what) {
427         case PROC_EVENT_FORK:
428                 __process_event_fork(msg.proc_ev.event_data.fork.child_tgid,
429                                      msg.proc_ev.event_data.fork.child_pid);
430                 break;
431         case PROC_EVENT_EXEC:
432                 __process_event_exec(msg.proc_ev.event_data.exec.process_tgid,
433                                      msg.proc_ev.event_data.exec.process_pid);
434                 break;
435         case PROC_EVENT_EXIT:
436                 __process_event_exit(msg.proc_ev.event_data.exit.process_tgid,
437                                      msg.proc_ev.event_data.exit.process_pid,
438                                      msg.proc_ev.event_data.exit.exit_code);
439                 break;
440         default:
441                 break;
442         }
443
444         return TRUE;
445 }
446
447 static int __subscribe_proc_events(void)
448 {
449         __STC_LOG_FUNC_ENTER__;
450         nl_connector_msg_s msg;
451         int ret;
452         int sock = nl_connector_sock;
453
454         if (sock == -1) {
455                 __STC_LOG_FUNC_EXIT__;
456                 return -1;
457         }
458
459         memset(&msg, 0, sizeof(nl_connector_msg_s));
460
461         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
462         msg.nl_hdr.nlmsg_pid = getpid();
463         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
464
465         msg.cn_msg.id.idx = CN_IDX_PROC;
466         msg.cn_msg.id.val = CN_VAL_PROC;
467         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
468
469         msg.cn_mcast = PROC_CN_MCAST_LISTEN;
470
471         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
472         if (ret == -1) {
473                 STC_LOGE("Error sending netlink connector message");
474                 __STC_LOG_FUNC_EXIT__;
475                 return -1;
476         }
477
478         __STC_LOG_FUNC_EXIT__;
479         return 0;
480 }
481
482 static int __unsubscribe_proc_events(void)
483 {
484         __STC_LOG_FUNC_ENTER__;
485         nl_connector_msg_s msg;
486         int ret;
487         int sock = nl_connector_sock;
488
489         if (sock == -1) {
490                 __STC_LOG_FUNC_EXIT__;
491                 return -1;
492         }
493
494         memset(&msg, 0, sizeof(nl_connector_msg_s));
495
496         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
497         msg.nl_hdr.nlmsg_pid = getpid();
498         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
499
500         msg.cn_msg.id.idx = CN_IDX_PROC;
501         msg.cn_msg.id.val = CN_VAL_PROC;
502         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
503
504         msg.cn_mcast = PROC_CN_MCAST_IGNORE;
505
506         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
507         if (ret == -1) {
508                 STC_LOGE("Error sending netlink connector message");
509                 __STC_LOG_FUNC_EXIT__;
510                 return -1;
511         }
512
513         __STC_LOG_FUNC_EXIT__;
514         return 0;
515 }
516
517 static bool __process_pid_cb(pid_t pid, void *user_data)
518 {
519         char cmdline[PROC_NAME_MAX] = {0, };
520         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
521
522         memset(status, 0x0, sizeof(status));
523
524         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
525             STC_ERROR_NONE == proc_get_status(pid, status)) {
526
527                 if (__check_excn(cmdline))
528                         return true;
529
530                 unsigned int i;
531                 proc_key_s key;
532                 proc_value_s value;
533
534                 memset(&key, 0x0, sizeof(proc_key_s));
535                 memset(&value, 0x0, sizeof(proc_value_s));
536
537                 key.pid = pid;
538                 for (i = 0; i < PROC_STATUS_CNT; ++i)
539                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
540                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
541
542                 __proc_tree_add(&key, &value);
543         }
544
545         return true;
546 }
547
548 int stc_plugin_procfs_initialize(void)
549 {
550         __STC_LOG_FUNC_ENTER__;
551
552         proc_tree = g_tree_new_full(__proc_tree_key_compare, NULL,
553                                     __proc_tree_key_free,
554                                     __proc_tree_value_free);
555
556         /* TODO: Fill proc tree with current procfs state */
557
558         __open_nl_connector_sock();
559         __subscribe_proc_events();
560         __STC_LOG_FUNC_EXIT__;
561         return STC_ERROR_NONE;
562 }
563
564 int stc_plugin_procfs_deinitialize(void)
565 {
566         __STC_LOG_FUNC_ENTER__;
567
568         if (nl_connector_sock == -1) {
569                 STC_LOGD("socket already closed");
570                 return STC_ERROR_NONE;
571         }
572
573         __unsubscribe_proc_events();
574         __close_nl_connector_sock();
575
576         g_tree_destroy(proc_tree);
577         proc_tree = NULL;
578
579         __STC_LOG_FUNC_EXIT__;
580         return STC_ERROR_NONE;
581 }
582
583 stc_error_e stc_plugin_procfs_load(void)
584 {
585         __STC_LOG_FUNC_ENTER__;
586
587         proc_foreach_pid(__process_pid_cb, NULL);
588
589         __STC_LOG_FUNC_EXIT__;
590         return STC_ERROR_NONE;
591 }
592
593 stc_error_e stc_plugin_procfs_status_changed(stc_cmd_type_e cmd,
594                                                 pid_t pid,
595                                                 const gchar *app_id,
596                                                 const gchar *pkg_id,
597                                                 stc_app_type_e app_type)
598 {
599         stc_error_e ret = STC_ERROR_NONE;
600
601         if ((pkg_id && app_id) && STC_DEBUG_LOG)
602                 STC_LOGD("cmd[%d] pkgid[%s] appid[%s] pid[%d] type[%d]",
603                         cmd, pkg_id, app_id, pid, app_type);
604
605         switch (cmd) {
606         case STC_CMD_SET_FOREGRD:
607         {
608                 uint32_t classid;
609                 char *bg_app_id;
610                 stc_app_value_s app_value;
611                 stc_proc_value_s proc_value;
612
613                 memset(&app_value, 0, sizeof(stc_app_value_s));
614                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
615
616                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
617
618                 app_value.type = app_type;
619                 app_value.processes = NULL;
620
621                 proc_value.pid = pid;
622                 proc_value.ground = STC_APP_STATE_FOREGROUND;
623
624                 classid = get_classid_by_app_id(bg_app_id, FALSE);
625                 stc_monitor_proc_remove(classid, pid);
626
627                 classid = get_classid_by_app_id(app_id, TRUE);
628
629                 stc_monitor_app_add(classid, app_id, pkg_id, app_value);
630                 stc_monitor_proc_add(classid, app_id, proc_value);
631                 stc_monitor_proc_update_ground(classid, app_id, proc_value);
632
633                 FREE(bg_app_id);
634                 break;
635         }
636         case STC_CMD_SET_BACKGRD:
637         {
638                 uint32_t classid;
639                 char *bg_app_id;
640                 stc_app_value_s app_value;
641                 stc_proc_value_s proc_value;
642
643                 memset(&app_value, 0, sizeof(stc_app_value_s));
644                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
645
646                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
647
648                 app_value.type = app_type;
649                 app_value.processes = NULL;
650
651                 proc_value.pid = pid;
652                 proc_value.ground = STC_APP_STATE_BACKGROUND;
653
654                 classid = get_classid_by_app_id(app_id, FALSE);
655                 stc_monitor_proc_remove(classid, pid);
656
657                 classid = get_classid_by_app_id(bg_app_id, TRUE);
658
659                 stc_monitor_app_add(classid, bg_app_id, pkg_id, app_value);
660                 stc_monitor_proc_add(classid, bg_app_id, proc_value);
661                 stc_monitor_proc_update_ground(classid, bg_app_id, proc_value);
662
663                 FREE(bg_app_id);
664                 break;
665         }
666         case STC_CMD_SET_SERVICE_LAUNCHED:
667         {
668                 uint32_t classid;
669                 char *bg_app_id;
670                 stc_app_value_s app_value;
671                 stc_proc_value_s proc_value;
672
673                 memset(&app_value, 0, sizeof(stc_app_value_s));
674                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
675
676                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
677
678                 app_value.type = app_type;
679                 app_value.processes = NULL;
680
681                 proc_value.pid = pid;
682                 proc_value.ground = STC_APP_STATE_BACKGROUND;
683
684                 classid = get_classid_by_app_id(bg_app_id, TRUE);
685
686                 stc_monitor_app_add(classid, bg_app_id, pkg_id, app_value);
687                 stc_monitor_proc_add(classid, bg_app_id, proc_value);
688
689                 FREE(bg_app_id);
690                 break;
691         }
692         case STC_CMD_SET_TERMINATED:
693         {
694                 uint32_t classid;
695                 char *bg_app_id;
696
697                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
698                 classid = get_classid_by_app_id(bg_app_id, FALSE);
699
700                 if (classid == STC_UNKNOWN_CLASSID)
701                         classid = get_classid_by_app_id(app_id, FALSE);
702
703                 stc_monitor_proc_remove(classid, pid);
704
705                 FREE(bg_app_id);
706                 break;
707         }
708         default:
709                 STC_LOGE("Unhandled command");
710                 ret = STC_ERROR_INVALID_PARAMETER;
711         }
712
713         return ret;
714 }
715
716 API stc_plugin_procfs_s stc_plugin_procfs = {
717         .initialize_plugin =
718                 stc_plugin_procfs_initialize,
719         .deinitialize_plugin =
720                 stc_plugin_procfs_deinitialize,
721         .procfs_load =
722                 stc_plugin_procfs_load,
723         .procfs_status_changed =
724                 stc_plugin_procfs_status_changed
725 };
726 //LCOV_EXCL_STOP