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