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