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