2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/connector.h>
27 #include <linux/cn_proc.h>
30 #include "stc-app-lifecycle.h"
31 #include "helper-procfs.h"
38 char cmdline[PROC_NAME_MAX];
39 char status[PROC_BUF_MAX];
42 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
43 struct nlmsghdr nl_hdr;
44 struct __attribute__ ((__packed__)) {
46 enum proc_cn_mcast_op cn_mcast;
50 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
51 struct nlmsghdr nl_hdr;
52 struct __attribute__ ((__packed__)) {
54 struct proc_event proc_ev;
56 } nl_connector_proc_event_s;
58 static int nl_connector_sock = -1;
59 static guint nl_connector_gsource_id = 0;
60 static GTree *proc_tree;
63 static gboolean __process_nl_connector_message(GIOChannel *source,
64 GIOCondition condition,
67 static int __proc_tree_key_compare(gconstpointer a, gconstpointer b,
68 gpointer UNUSED user_data)
70 proc_key_s *key_a = (proc_key_s *)a;
71 proc_key_s *key_b = (proc_key_s *)b;
73 return key_a->pid - key_b->pid;
76 static void __proc_tree_value_free(gpointer data)
78 proc_value_s *value = (proc_value_s *)data;
83 static void __proc_tree_key_free(gpointer data)
85 proc_key_s *key = (proc_key_s *)data;
90 static proc_value_s * __proc_tree_lookup(const proc_key_s *key)
94 if (proc_tree == NULL) {
95 STC_LOGE("tree is null");
99 lookup = g_tree_lookup(proc_tree, key);
103 static void __proc_tree_add(proc_key_s *key,
106 if (proc_tree == NULL) {
107 STC_LOGE("tree is null");
111 g_tree_insert(proc_tree, key, value);
113 stc_manager_app_status_changed(STC_CMD_SET_SERVICE_LAUNCHED, key->pid,
114 value->cmdline, value->cmdline,
115 STC_APP_TYPE_SERVICE);
118 static void __proc_tree_remove(const proc_key_s *key)
120 if (proc_tree == NULL) {
121 STC_LOGE("tree is null");
125 stc_manager_app_status_changed(STC_CMD_SET_TERMINATED, key->pid, NULL,
126 NULL, STC_APP_TYPE_NONE);
127 g_tree_remove(proc_tree, key);
130 static void __open_nl_connector_sock(void)
132 __STC_LOG_FUNC_ENTER__;
133 GIOChannel *gio = NULL;
135 if (nl_connector_sock != -1 &&
136 nl_connector_gsource_id != 0) {
137 STC_LOGE("Socket is already open");
138 __STC_LOG_FUNC_EXIT__;
142 if (nl_connector_sock != -1) {
143 close(nl_connector_sock);
144 nl_connector_sock = -1;
147 if (nl_connector_gsource_id != 0) {
148 g_source_remove(nl_connector_gsource_id);
149 nl_connector_gsource_id = 0;
152 nl_connector_sock = create_netlink(NETLINK_CONNECTOR, CN_IDX_PROC);
153 if (nl_connector_sock == -1) {
154 __STC_LOG_FUNC_EXIT__;
158 gio = g_io_channel_unix_new(nl_connector_sock);
159 nl_connector_gsource_id =
160 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
161 (GIOFunc) __process_nl_connector_message,
163 g_io_channel_unref(gio);
164 __STC_LOG_FUNC_EXIT__;
167 static void __close_nl_connector_sock(void)
169 __STC_LOG_FUNC_ENTER__;
170 if (nl_connector_sock != -1) {
171 close(nl_connector_sock);
172 nl_connector_sock = -1;
175 if (nl_connector_gsource_id != 0) {
176 g_source_remove(nl_connector_gsource_id);
177 nl_connector_gsource_id = 0;
179 __STC_LOG_FUNC_EXIT__;
182 static void __reopen_nl_connector_sock(void)
184 __close_nl_connector_sock();
185 __open_nl_connector_sock();
188 stc_error_e stc_manager_app_status_changed(stc_cmd_type_e cmd,
192 stc_app_type_e app_type)
194 __STC_LOG_FUNC_ENTER__;
195 stc_error_e ret = STC_ERROR_NONE;
198 case STC_CMD_SET_FOREGRD:
200 stc_app_key_s app_key;
201 stc_app_value_s app_value;
202 stc_process_key_s proc_key;
203 stc_process_value_s proc_value;
205 memset(&app_key, 0, sizeof(stc_app_key_s));
206 memset(&app_value, 0, sizeof(stc_app_value_s));
207 memset(&proc_key, 0, sizeof(stc_process_key_s));
208 memset(&proc_value, 0, sizeof(stc_process_value_s));
210 app_key.pkg_id = g_strdup(pkg_id);
211 app_key.app_id = g_strdup(app_id);
213 app_value.type = app_type;
214 app_value.processes = NULL;
218 proc_value.ground = STC_APP_STATE_FOREGROUND;
220 stc_monitor_application_add(app_key, app_value);
221 stc_monitor_process_add(app_key, proc_key, proc_value);
222 stc_monitor_process_update_ground(app_key, proc_key,
223 STC_APP_STATE_FOREGROUND);
225 FREE(app_key.pkg_id);
226 FREE(app_key.app_id);
229 case STC_CMD_SET_BACKGRD:
231 stc_app_key_s app_key;
232 stc_app_value_s app_value;
233 stc_process_key_s proc_key;
234 stc_process_value_s proc_value;
236 memset(&app_key, 0, sizeof(stc_app_key_s));
237 memset(&app_value, 0, sizeof(stc_app_value_s));
238 memset(&proc_key, 0, sizeof(stc_process_key_s));
239 memset(&proc_value, 0, sizeof(stc_process_value_s));
241 app_key.pkg_id = g_strdup(pkg_id);
242 app_key.app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX,
245 app_value.type = app_type;
246 app_value.processes = NULL;
250 proc_value.ground = STC_APP_STATE_BACKGROUND;
252 stc_monitor_application_add(app_key, app_value);
253 stc_monitor_process_add(app_key, proc_key, proc_value);
254 stc_monitor_process_update_ground(app_key, proc_key,
255 STC_APP_STATE_BACKGROUND);
257 FREE(app_key.pkg_id);
258 FREE(app_key.app_id);
261 case STC_CMD_SET_SERVICE_LAUNCHED:
263 stc_app_key_s app_key;
264 stc_app_value_s app_value;
265 stc_process_key_s proc_key;
266 stc_process_value_s proc_value;
268 memset(&app_key, 0, sizeof(stc_app_key_s));
269 memset(&app_value, 0, sizeof(stc_app_value_s));
270 memset(&proc_key, 0, sizeof(stc_process_key_s));
271 memset(&proc_value, 0, sizeof(stc_process_value_s));
273 app_key.pkg_id = g_strdup(pkg_id);
274 app_key.app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX,
277 app_value.type = app_type;
278 app_value.processes = NULL;
282 /* services will run always in background. */
283 proc_value.ground = STC_APP_STATE_BACKGROUND;
285 stc_monitor_application_add(app_key, app_value);
286 stc_monitor_process_add(app_key, proc_key, proc_value);
288 FREE(app_key.pkg_id);
289 g_free(app_key.app_id);
292 case STC_CMD_SET_TERMINATED:
294 stc_monitor_process_remove(pid);
298 STC_LOGE("Unhandled command");
299 ret = STC_ERROR_INVALID_PARAMETER;
302 __STC_LOG_FUNC_EXIT__;
306 static void __process_event_exec(int tid, int pid)
308 char cmdline[PROC_NAME_MAX] = {0, };
309 char status[PROC_BUF_MAX] = {0, };
311 if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
312 STC_ERROR_NONE == proc_get_status(pid, status, PROC_BUF_MAX)) {
314 if (!g_strcmp0(cmdline, "iptables") || !g_strcmp0(cmdline, "ip6tables") ||
315 !g_strcmp0(cmdline, "modprobe") || !g_strcmp0(cmdline, "net-cls-release")) {
322 key = MALLOC0(proc_key_s, 1);
324 STC_LOGE("memory allocation failed");
328 value = MALLOC0(proc_value_s, 1);
330 STC_LOGE("memory allocation failed");
336 g_strlcpy(value->status, status, sizeof(value->status));
337 g_strlcpy(value->cmdline, cmdline, sizeof(value->cmdline));
339 __proc_tree_add(key, value);
341 STC_LOGD("EXEC:pid=%d,tgid=%d\t[%s]\t[%s]", pid, tid, status,
346 static void __process_event_exit(int tid, int pid, int exit_code)
349 proc_value_s *lookup;
352 lookup = __proc_tree_lookup(&key);
353 if (lookup == NULL) /* unmonitored process */
356 __proc_tree_remove(&key);
358 STC_LOGD("EXIT:pid=%d,%d ruid=%d,euid=%d", pid, tid, exit_code);
361 static gboolean __process_nl_connector_message(GIOChannel *source,
362 GIOCondition condition,
366 int sock = g_io_channel_unix_get_fd(source);
367 nl_connector_proc_event_s msg;
369 if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
370 (condition & G_IO_NVAL)) {
371 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
373 STC_LOGE("Netlink Connector socket received G_IO event, closing"
374 " socket. G_IO_ERR [%d], G_IO_HUP [%d], G_IO_NVAL [%s]",
375 (condition & G_IO_ERR), (condition & G_IO_HUP),
376 (condition & G_IO_NVAL));
377 __reopen_nl_connector_sock();
378 __STC_LOG_FUNC_EXIT__;
382 memset(&msg, 0, sizeof(nl_connector_proc_event_s));
384 ret = read(sock, &msg, sizeof(nl_connector_proc_event_s));
386 __STC_LOG_FUNC_EXIT__;
390 switch (msg.proc_ev.what) {
391 case PROC_EVENT_EXEC:
392 __process_event_exec(msg.proc_ev.event_data.exec.process_pid,
393 msg.proc_ev.event_data.exec.process_tgid);
395 case PROC_EVENT_EXIT:
396 __process_event_exit(msg.proc_ev.event_data.exit.process_pid,
397 msg.proc_ev.event_data.exit.process_tgid,
398 msg.proc_ev.event_data.exit.exit_code);
407 static int __subscribe_proc_events(void)
409 __STC_LOG_FUNC_ENTER__;
410 nl_connector_msg_s msg;
412 int sock = nl_connector_sock;
415 __STC_LOG_FUNC_EXIT__;
419 memset(&msg, 0, sizeof(nl_connector_msg_s));
421 msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
422 msg.nl_hdr.nlmsg_pid = getpid();
423 msg.nl_hdr.nlmsg_type = NLMSG_DONE;
425 msg.cn_msg.id.idx = CN_IDX_PROC;
426 msg.cn_msg.id.val = CN_VAL_PROC;
427 msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
429 msg.cn_mcast = PROC_CN_MCAST_LISTEN;
431 ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
433 STC_LOGE("Error sending netlink connector message");
434 __STC_LOG_FUNC_EXIT__;
438 __STC_LOG_FUNC_EXIT__;
442 static int __unsubscribe_proc_events(void)
444 __STC_LOG_FUNC_ENTER__;
445 nl_connector_msg_s msg;
447 int sock = nl_connector_sock;
450 __STC_LOG_FUNC_EXIT__;
454 memset(&msg, 0, sizeof(nl_connector_msg_s));
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;
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);
464 msg.cn_mcast = PROC_CN_MCAST_IGNORE;
466 ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
468 STC_LOGE("Error sending netlink connector message");
469 __STC_LOG_FUNC_EXIT__;
473 __STC_LOG_FUNC_EXIT__;
477 void stc_app_lifecycle_monitor_init(void)
479 __STC_LOG_FUNC_ENTER__;
481 proc_tree = g_tree_new_full(__proc_tree_key_compare, NULL,
482 __proc_tree_key_free,
483 __proc_tree_value_free);
485 /* TODO: Fill proc tree with current procfs state */
487 __open_nl_connector_sock();
488 __subscribe_proc_events();
489 __STC_LOG_FUNC_EXIT__;
492 void stc_app_lifecycle_monitor_deinit(void)
494 __STC_LOG_FUNC_ENTER__;
496 if (nl_connector_sock == -1) {
497 STC_LOGE("socket already closed");
501 __unsubscribe_proc_events();
502 __close_nl_connector_sock();
504 g_tree_destroy(proc_tree);
507 __STC_LOG_FUNC_EXIT__;