82b301c5b9ba5026b2f574729b229eecbd0ae0a0
[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-procfs.h"
33
34 //LCOV_EXCL_START
35 typedef struct {
36         pid_t pid;
37 } proc_key_s;
38
39 typedef struct {
40         char cmdline[PROC_NAME_MAX];
41         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
42 } proc_value_s;
43
44 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
45         struct nlmsghdr nl_hdr;
46         struct __attribute__ ((__packed__)) {
47                 struct cn_msg cn_msg;
48                 enum proc_cn_mcast_op cn_mcast;
49         };
50 } nl_connector_msg_s;
51
52 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
53         struct nlmsghdr nl_hdr;
54         struct __attribute__ ((__packed__)) {
55                 struct cn_msg cn_msg;
56                 struct proc_event proc_ev;
57         };
58 } nl_connector_proc_event_s;
59
60 static int nl_connector_sock = -1;
61 static guint nl_connector_gsource_id = 0;
62 static GTree *proc_tree;
63
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 [\033[1;35m%s\033[0;m] "
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) {
139                 if (parent != NULL)
140                         STC_LOGD("\033[0;35mPARENT\033[0;m: tgid[\033[1;33m%s\033[0;m] pid[%s] "
141                                 "ppid[\033[1;35m%s\033[0;m] 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)
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 {
203         if (proc_tree == NULL) {
204                 STC_LOGE("tree is null");
205                 return;
206         }
207
208         stc_plugin_procfs_status_changed(STC_CMD_SET_TERMINATED, key->pid, NULL,
209                                        NULL, STC_APP_TYPE_NONE);
210
211         g_tree_remove(proc_tree, key);
212
213         /*
214         __proc_tree_printall();
215         */
216 }
217
218 static gboolean __check_excn(char *cmdline)
219 {
220         stc_error_e ret = STC_ERROR_NONE;
221
222         if (cmdline[0] == '(')
223                 return TRUE;
224
225         ret = stc_monitor_check_excn_by_cmdline(cmdline);
226         if (ret == STC_ERROR_UNINITIALIZED ||
227                 ret == STC_ERROR_NO_DATA)
228                 return FALSE;
229         else
230                 return TRUE;
231 }
232
233 static void __open_nl_connector_sock(void)
234 {
235         __STC_LOG_FUNC_ENTER__;
236         GIOChannel *gio = NULL;
237
238         if (nl_connector_sock != -1 &&
239             nl_connector_gsource_id != 0) {
240                 STC_LOGE("Socket is already open");
241                 __STC_LOG_FUNC_EXIT__;
242                 return;
243         }
244
245         if (nl_connector_sock != -1) {
246                 close(nl_connector_sock);
247                 nl_connector_sock = -1;
248         }
249
250         if (nl_connector_gsource_id != 0) {
251                 g_source_remove(nl_connector_gsource_id);
252                 nl_connector_gsource_id = 0;
253         }
254
255         nl_connector_sock = create_netlink(NETLINK_CONNECTOR, CN_IDX_PROC);
256         if (nl_connector_sock == -1) {
257                 __STC_LOG_FUNC_EXIT__;
258                 return;
259         }
260
261         gio = g_io_channel_unix_new(nl_connector_sock);
262         nl_connector_gsource_id =
263                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
264                                (GIOFunc) __process_nl_connector_message,
265                                NULL);
266         g_io_channel_unref(gio);
267         __STC_LOG_FUNC_EXIT__;
268 }
269
270 static void __close_nl_connector_sock(void)
271 {
272         __STC_LOG_FUNC_ENTER__;
273         if (nl_connector_sock != -1) {
274                 close(nl_connector_sock);
275                 nl_connector_sock = -1;
276         }
277
278         if (nl_connector_gsource_id != 0) {
279                 g_source_remove(nl_connector_gsource_id);
280                 nl_connector_gsource_id = 0;
281         }
282         __STC_LOG_FUNC_EXIT__;
283 }
284
285 static void __reopen_nl_connector_sock(void)
286 {
287         __close_nl_connector_sock();
288         __open_nl_connector_sock();
289 }
290
291 static void __process_event_fork(int tgid, int pid)
292 {
293         char cmdline[PROC_NAME_MAX] = {0, };
294         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
295
296         /* TODO: Add newly created thread to the process tasks */
297         if (tgid != pid)
298                 return;
299
300         memset(status, 0x0, sizeof(status));
301
302         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
303             STC_ERROR_NONE == proc_get_status(pid, status)) {
304
305                 if (__check_excn(cmdline)) {
306                         if (STC_DEBUG_LOG)
307                                 STC_LOGD("[%s] monitoring is excepted", cmdline);
308                         return;
309                 }
310
311                 unsigned int i;
312                 proc_key_s key;
313                 proc_value_s value;
314
315                 memset(&key, 0x0, sizeof(proc_key_s));
316                 memset(&value, 0x0, sizeof(proc_value_s));
317
318                 key.pid = tgid;
319                 for (i = 0; i < PROC_STATUS_CNT; ++i)
320                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
321                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
322
323                 if (STC_DEBUG_LOG)
324                         STC_LOGD("\033[1;34mFORK\033[0;m: tgid[\033[1;33m%d\033[0;m] ppid=[\033[1;35m%s\033[0;m] "
325                                 "cmdline[\033[0;34m%s\033[0;m] pid[%d]", 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                         if (STC_DEBUG_LOG)
347                                 STC_LOGD("[%s] monitoring is excepted", cmdline);
348                         return;
349                 }
350
351                 unsigned int i;
352                 proc_key_s key;
353                 proc_value_s value;
354
355                 memset(&key, 0x0, sizeof(proc_key_s));
356                 memset(&value, 0x0, sizeof(proc_value_s));
357
358                 key.pid = tgid;
359                 for (i = 0; i < PROC_STATUS_CNT; ++i)
360                         g_strlcpy(value.status[i], status[i],
361                                   sizeof(value.status[i]));
362                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
363
364                 if (STC_DEBUG_LOG)
365                         STC_LOGD("\033[1;32mEXEC\033[0;m: tgid[\033[1;33m%d\033[0;m] ppid=[\033[1;35m%s\033[0;m] "
366                                 "cmdline[\033[0;34m%s\033[0;m] pid[%d]", tgid, status[PROC_STATUS_PPID], cmdline, pid);
367
368                 __proc_tree_add(&key, &value);
369         }
370 }
371
372 static void __process_event_exit(int tgid, int pid, int exit_code)
373 {
374         proc_key_s key;
375         proc_value_s *lookup;
376
377         if (tgid != pid)
378                 return;
379
380         key.pid = tgid;
381         lookup = __proc_tree_lookup(&key);
382         if (lookup == NULL) /* unmonitored process */
383                 return;
384
385         if (STC_DEBUG_LOG)
386                 STC_LOGD("\033[1;31mEXIT\033[0;m: tgid[\033[1;33m%d\033[0;m] "
387                         "pid[%d] exitcode[\033[0;31m%d\033[0;m]", tgid, pid, exit_code);
388
389         __proc_tree_remove(&key);
390 }
391
392 static gboolean __process_nl_connector_message(GIOChannel *source,
393                                                GIOCondition condition,
394                                                gpointer user_data)
395 {
396         int ret;
397         int sock = g_io_channel_unix_get_fd(source);
398         nl_connector_proc_event_s msg;
399
400         if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
401             (condition & G_IO_NVAL)) {
402                 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
403
404                 STC_LOGE("Netlink Connector socket received G_IO event, closing"
405                          " socket. G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
406                          (condition & G_IO_ERR), (condition & G_IO_HUP),
407                          (condition & G_IO_NVAL));
408                 __reopen_nl_connector_sock();
409                 __STC_LOG_FUNC_EXIT__;
410                 return FALSE;
411         }
412
413         memset(&msg, 0, sizeof(nl_connector_proc_event_s));
414
415         ret = read(sock, &msg, sizeof(nl_connector_proc_event_s));
416         if (ret == 0) {
417                 __STC_LOG_FUNC_EXIT__;
418                 return TRUE;
419         }
420
421         switch (msg.proc_ev.what) {
422         case PROC_EVENT_FORK:
423                 __process_event_fork(msg.proc_ev.event_data.fork.child_tgid,
424                                      msg.proc_ev.event_data.fork.child_pid);
425                 break;
426         case PROC_EVENT_EXEC:
427                 __process_event_exec(msg.proc_ev.event_data.exec.process_tgid,
428                                      msg.proc_ev.event_data.exec.process_pid);
429                 break;
430         case PROC_EVENT_EXIT:
431                 __process_event_exit(msg.proc_ev.event_data.exit.process_tgid,
432                                      msg.proc_ev.event_data.exit.process_pid,
433                                      msg.proc_ev.event_data.exit.exit_code);
434                 break;
435         default:
436                 ; /* Do nothing */
437         }
438
439         return TRUE;
440 }
441
442 static int __subscribe_proc_events(void)
443 {
444         __STC_LOG_FUNC_ENTER__;
445         nl_connector_msg_s msg;
446         int ret;
447         int sock = nl_connector_sock;
448
449         if (sock == -1) {
450                 __STC_LOG_FUNC_EXIT__;
451                 return -1;
452         }
453
454         memset(&msg, 0, sizeof(nl_connector_msg_s));
455
456         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
457         msg.nl_hdr.nlmsg_pid = getpid();
458         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
459
460         msg.cn_msg.id.idx = CN_IDX_PROC;
461         msg.cn_msg.id.val = CN_VAL_PROC;
462         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
463
464         msg.cn_mcast = PROC_CN_MCAST_LISTEN;
465
466         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
467         if (ret == -1) {
468                 STC_LOGE("Error sending netlink connector message");
469                 __STC_LOG_FUNC_EXIT__;
470                 return -1;
471         }
472
473         __STC_LOG_FUNC_EXIT__;
474         return 0;
475 }
476
477 static int __unsubscribe_proc_events(void)
478 {
479         __STC_LOG_FUNC_ENTER__;
480         nl_connector_msg_s msg;
481         int ret;
482         int sock = nl_connector_sock;
483
484         if (sock == -1) {
485                 __STC_LOG_FUNC_EXIT__;
486                 return -1;
487         }
488
489         memset(&msg, 0, sizeof(nl_connector_msg_s));
490
491         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
492         msg.nl_hdr.nlmsg_pid = getpid();
493         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
494
495         msg.cn_msg.id.idx = CN_IDX_PROC;
496         msg.cn_msg.id.val = CN_VAL_PROC;
497         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
498
499         msg.cn_mcast = PROC_CN_MCAST_IGNORE;
500
501         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
502         if (ret == -1) {
503                 STC_LOGE("Error sending netlink connector message");
504                 __STC_LOG_FUNC_EXIT__;
505                 return -1;
506         }
507
508         __STC_LOG_FUNC_EXIT__;
509         return 0;
510 }
511
512 static bool __process_pid_cb(pid_t pid, void *user_data)
513 {
514         char cmdline[PROC_NAME_MAX] = {0, };
515         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
516
517         memset(status, 0x0, sizeof(status));
518
519         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
520             STC_ERROR_NONE == proc_get_status(pid, status)) {
521
522                 if (__check_excn(cmdline))
523                         return true;
524
525                 unsigned int i;
526                 proc_key_s key;
527                 proc_value_s value;
528
529                 memset(&key, 0x0, sizeof(proc_key_s));
530                 memset(&value, 0x0, sizeof(proc_value_s));
531
532                 key.pid = pid;
533                 for (i = 0; i < PROC_STATUS_CNT; ++i)
534                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
535                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
536
537                 __proc_tree_add(&key, &value);
538         }
539
540         return true;
541 }
542
543 int stc_plugin_procfs_initialize(void)
544 {
545         __STC_LOG_FUNC_ENTER__;
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         __subscribe_proc_events();
555         __STC_LOG_FUNC_EXIT__;
556         return STC_ERROR_NONE;
557 }
558
559 int stc_plugin_procfs_deinitialize(void)
560 {
561         __STC_LOG_FUNC_ENTER__;
562
563         if (nl_connector_sock == -1) {
564                 STC_LOGD("socket already closed");
565                 return STC_ERROR_NONE;
566         }
567
568         __unsubscribe_proc_events();
569         __close_nl_connector_sock();
570
571         g_tree_destroy(proc_tree);
572         proc_tree = NULL;
573
574         __STC_LOG_FUNC_EXIT__;
575         return STC_ERROR_NONE;
576 }
577
578 stc_error_e stc_plugin_procfs_load(void)
579 {
580         __STC_LOG_FUNC_ENTER__;
581
582         proc_foreach_pid(__process_pid_cb, NULL);
583
584         __STC_LOG_FUNC_EXIT__;
585         return STC_ERROR_NONE;
586 }
587
588 stc_error_e stc_plugin_procfs_status_changed(stc_cmd_type_e cmd, pid_t pid,
589                                              const gchar *app_id,
590                                              const gchar *pkg_id,
591                                              stc_app_type_e app_type)
592 {
593         stc_error_e ret = STC_ERROR_NONE;
594
595         if ((pkg_id && app_id) && STC_DEBUG_LOG)
596                 STC_LOGD("cmd [%d] pkgid [%s] appid [%s] pid[%d] type [%d]",
597                         cmd, pkg_id, app_id, pid, app_type);
598
599         switch (cmd) {
600         case STC_CMD_SET_FOREGRD:
601         {
602                 stc_app_key_s app_key;
603                 stc_app_value_s app_value;
604                 stc_process_key_s proc_key;
605                 stc_process_value_s proc_value;
606
607                 memset(&app_key, 0, sizeof(stc_app_key_s));
608                 memset(&app_value, 0, sizeof(stc_app_value_s));
609                 memset(&proc_key, 0, sizeof(stc_process_key_s));
610                 memset(&proc_value, 0, sizeof(stc_process_value_s));
611
612                 app_key.pkg_id = g_strdup(pkg_id);
613                 app_key.app_id = g_strdup(app_id);
614
615                 app_value.type = app_type;
616                 app_value.processes = NULL;
617
618                 proc_key.pid = pid;
619
620                 proc_value.ground = STC_APP_STATE_FOREGROUND;
621
622                 stc_monitor_application_add(app_key, app_value);
623                 stc_monitor_process_add(app_key, proc_key, proc_value);
624                 stc_monitor_process_update_ground(app_key, proc_key,
625                                                   STC_APP_STATE_FOREGROUND);
626
627                 FREE(app_key.pkg_id);
628                 FREE(app_key.app_id);
629                 break;
630         }
631         case STC_CMD_SET_BACKGRD:
632         {
633                 stc_app_key_s app_key;
634                 stc_app_value_s app_value;
635                 stc_process_key_s proc_key;
636                 stc_process_value_s proc_value;
637
638                 memset(&app_key, 0, sizeof(stc_app_key_s));
639                 memset(&app_value, 0, sizeof(stc_app_value_s));
640                 memset(&proc_key, 0, sizeof(stc_process_key_s));
641                 memset(&proc_value, 0, sizeof(stc_process_value_s));
642
643                 app_key.pkg_id = g_strdup(pkg_id);
644                 app_key.app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX,
645                                              NULL);
646
647                 app_value.type = app_type;
648                 app_value.processes = NULL;
649
650                 proc_key.pid = pid;
651
652                 proc_value.ground = STC_APP_STATE_BACKGROUND;
653
654                 stc_monitor_application_add(app_key, app_value);
655                 stc_monitor_process_add(app_key, proc_key, proc_value);
656                 stc_monitor_process_update_ground(app_key, proc_key,
657                                                   STC_APP_STATE_BACKGROUND);
658
659                 FREE(app_key.pkg_id);
660                 FREE(app_key.app_id);
661                 break;
662         }
663         case STC_CMD_SET_SERVICE_LAUNCHED:
664         {
665                 stc_app_key_s app_key;
666                 stc_app_value_s app_value;
667                 stc_process_key_s proc_key;
668                 stc_process_value_s proc_value;
669
670                 memset(&app_key, 0, sizeof(stc_app_key_s));
671                 memset(&app_value, 0, sizeof(stc_app_value_s));
672                 memset(&proc_key, 0, sizeof(stc_process_key_s));
673                 memset(&proc_value, 0, sizeof(stc_process_value_s));
674
675                 app_key.pkg_id = g_strdup(pkg_id);
676                 app_key.app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX,
677                                              NULL);
678
679                 app_value.type = app_type;
680                 app_value.processes = NULL;
681
682                 proc_key.pid = pid;
683
684                 /* services will run always in background. */
685                 proc_value.ground = STC_APP_STATE_BACKGROUND;
686
687                 stc_monitor_application_add(app_key, app_value);
688                 stc_monitor_process_add(app_key, proc_key, proc_value);
689
690                 FREE(app_key.pkg_id);
691                 g_free(app_key.app_id);
692                 break;
693         }
694         case STC_CMD_SET_TERMINATED:
695         {
696                 stc_monitor_process_remove(pid);
697                 break;
698         }
699         default:
700                 STC_LOGE("Unhandled command");
701                 ret = STC_ERROR_INVALID_PARAMETER;
702         }
703
704         return ret;
705 }
706
707 API stc_plugin_procfs_s stc_plugin_procfs = {
708         .initialize_plugin =
709                 stc_plugin_procfs_initialize,
710         .deinitialize_plugin =
711                 stc_plugin_procfs_deinitialize,
712         .procfs_load =
713                 stc_plugin_procfs_load,
714         .procfs_status_changed =
715                 stc_plugin_procfs_status_changed
716 };
717 //LCOV_EXCL_STOP