4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 #include <sys/types.h>
25 #include <device-node.h>
30 #include <vconf-keys.h>
33 #include "core/data.h"
34 #include "core/queue.h"
36 #include "core/common.h"
37 #include "core/devices.h"
38 #include "core/device-notifier.h"
39 #include "display/enhance.h"
40 #include "proc-handler.h"
41 #include "core/edbus-handler.h"
43 #define LIMITED_PROCESS_OOMADJ 15
45 #define PROCESS_VIP "process_vip"
46 #define PROCESS_PERMANENT "process_permanent"
47 #define OOMADJ_SET "oomadj_set"
49 #define PREDEF_BACKGRD "backgrd"
50 #define PREDEF_FOREGRD "foregrd"
51 #define PREDEF_ACTIVE "active"
52 #define PREDEF_INACTIVE "inactive"
53 #define PROCESS_GROUP_SET "process_group_set"
55 #define VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE "memory/private/sysman/siop_disable"
58 #define SIOP_CTRL_LEVEL_MASK 0xFFFF
59 #define SIOP_CTRL_LEVEL(val) ((val & SIOP_CTRL_LEVEL_MASK) << 16)
60 #define SIOP_CTRL_VALUE(s, r) (s | (r << 4))
61 #define SIOP_VALUE(d, val) ((d) * (val & 0xF))
62 #define REAR_VALUE(val) (val >> 4)
64 #define SIGNAL_SIOP_CHANGED "ChangedSiop"
65 #define SIGNAL_REAR_CHANGED "ChangedRear"
66 #define SIOP_LEVEL_GET "GetSiopLevel"
67 #define REAR_LEVEL_GET "GetRearLevel"
68 #define SIOP_LEVEL_SET "SetSiopLevel"
70 #define SIGNAL_NAME_OOMADJ_SET "OomadjSet"
72 enum SIOP_DOMAIN_TYPE {
79 static int siop_domain = SIOP_POSITIVE;
86 typedef struct _node {
91 static Node *head = NULL;
93 static Node *find_node(pid_t pid)
105 static Node *add_node(pid_t pid)
109 n = (Node *) malloc(sizeof(Node));
111 _E("Not enough memory, add cond. fail");
122 static int del_node(Node *n)
135 prev->next = t->next;
148 int cur_siop_level(void)
150 return SIOP_VALUE(siop_domain, siop);
153 static void siop_level_action(int level)
155 int val = SIOP_CTRL_LEVEL(level);
157 static int siop_level = 0;
158 static int rear_level = 0;
159 static int initialized = 0;
160 static int domain = 0;
164 if (initialized && siop == level && mode == old && domain == siop_domain)
168 domain = siop_domain;
169 if (siop_domain == SIOP_NEGATIVE)
174 device_set_property(DEVICE_TYPE_POWER, PROP_POWER_SIOP_CONTROL, val);
176 val = SIOP_VALUE(siop_domain, level);
177 if (siop_level != val) {
179 snprintf(str_level, sizeof(str_level), "%d", siop_level);
181 _I("broadcast siop %s", str_level);
182 broadcast_edbus_signal(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
183 SIGNAL_SIOP_CHANGED, "i", arr);
186 val = REAR_VALUE(level);
187 if (rear_level != val) {
189 snprintf(str_level, sizeof(str_level), "%d", rear_level);
191 _I("broadcast rear %s", str_level);
192 broadcast_edbus_signal(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
193 SIGNAL_REAR_CHANGED, "i", arr);
195 _I("level is d:%d(0x%x) s:%d r:%d", siop_domain, siop, siop_level, rear_level);
198 static int siop_changed(int argc, char **argv)
209 if (argc != 2 || argv[0] == NULL) {
210 _E("fail to check value");
217 level = atoi(argv[0]);
218 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_ELVSS_CONTROL, level);
219 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_SIOP_LEVEL, &level);
223 if (level <= SIOP_NEGATIVE)
224 siop_domain = SIOP_NEGATIVE;
226 siop_domain = SIOP_POSITIVE;
227 siop_level = siop_domain * level;
233 level = atoi(argv[1]);
234 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_REAR_LEVEL, &level) == 0)
238 level = SIOP_CTRL_VALUE(siop_level, rear_level);
239 siop_level_action(level);
244 static int siop_mode_lcd(keynode_t *key_nodes, void *data)
247 if (vconf_get_int(VCONFKEY_PM_STATE, &pm_state) != 0)
248 _E("Fail to get vconf value for pm state\n");
249 if (pm_state == VCONFKEY_PM_STATE_LCDOFF)
253 siop_level_action(siop);
257 static void memcg_move_group(int pid, int oom_score_adj)
262 char exe_name[PATH_MAX];
264 if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0) {
265 _E("fail to get process name(%d)", pid);
269 _SD("memcg_move_group : %s, pid = %d", exe_name, pid);
270 if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED)
271 sprintf(buf, "/sys/fs/cgroup/memory/background/cgroup.procs");
272 else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED && oom_score_adj < OOMADJ_BACKGRD_LOCKED)
273 sprintf(buf, "/sys/fs/cgroup/memory/foreground/cgroup.procs");
280 size = sprintf(buf, "%d", pid);
281 if (fwrite(buf, size, 1, f) != 1)
282 _E("fwrite cgroup tasks : %d\n", pid);;
286 int get_oom_score_adj(int pid, int *oom_score_adj)
294 fp = open_proc_oom_score_adj_file(pid, "r");
297 if (fgets(buf, PATH_MAX, fp) == NULL) {
302 *oom_score_adj = atoi(buf);
307 int set_oom_score_adj(pid_t pid, int new_oom_score_adj)
310 int old_oom_score_adj;
311 char exe_name[PATH_MAX];
313 if (get_cmdline_name(pid, exe_name, PATH_MAX) < 0)
314 snprintf(exe_name, sizeof(exe_name), "Unknown (maybe dead)");
316 if (get_oom_score_adj(pid, &old_oom_score_adj) < 0)
319 _SI("Process %s, pid %d, old_oom_score_adj %d new_oom_score_adj %d",
320 exe_name, pid, old_oom_score_adj, new_oom_score_adj);
322 if (new_oom_score_adj < OOMADJ_SU)
323 new_oom_score_adj = OOMADJ_SU;
325 fp = open_proc_oom_score_adj_file(pid, "w");
329 fprintf(fp, "%d", new_oom_score_adj);
335 int set_su_oom_score_adj(pid_t pid)
337 return set_oom_score_adj(pid, OOMADJ_SU);
340 int check_oom_score_adj(int oom_score_adj)
342 if (oom_score_adj != OOMADJ_FOREGRD_LOCKED && oom_score_adj != OOMADJ_FOREGRD_UNLOCKED)
347 int set_oom_score_adj_action(int argc, char **argv)
351 int new_oom_score_adj = 0;
355 if ((pid = atoi(argv[0])) < 0 || (new_oom_score_adj = atoi(argv[1])) <= -20)
358 _I("OOMADJ_SET : pid %d, new_oom_score_adj %d", pid, new_oom_score_adj);
360 fp = open_proc_oom_score_adj_file(pid, "w");
363 if (new_oom_score_adj < OOMADJ_SU)
364 new_oom_score_adj = OOMADJ_SU;
365 fprintf(fp, "%d", new_oom_score_adj);
368 memcg_move_group(pid, new_oom_score_adj);
372 int set_active_action(int argc, char **argv)
376 int oom_score_adj = 0;
380 if ((pid = atoi(argv[0])) < 0)
383 if (get_oom_score_adj(pid, &oom_score_adj) < 0)
386 switch (oom_score_adj) {
387 case OOMADJ_FOREGRD_LOCKED:
388 case OOMADJ_BACKGRD_LOCKED:
392 case OOMADJ_FOREGRD_UNLOCKED:
393 ret = set_oom_score_adj((pid_t) pid, OOMADJ_FOREGRD_LOCKED);
395 case OOMADJ_BACKGRD_UNLOCKED:
396 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
399 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
402 if(oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
403 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
405 _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
410 set_enhance_pid(pid);
414 int set_inactive_action(int argc, char **argv)
418 int oom_score_adj = 0;
422 if ((pid = atoi(argv[0])) < 0)
425 if (get_oom_score_adj(pid, &oom_score_adj) < 0)
428 switch (oom_score_adj) {
429 case OOMADJ_FOREGRD_UNLOCKED:
430 case OOMADJ_BACKGRD_UNLOCKED:
434 case OOMADJ_FOREGRD_LOCKED:
435 ret = set_oom_score_adj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
437 case OOMADJ_BACKGRD_LOCKED:
438 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
441 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
444 if(oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
447 _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
453 set_enhance_pid(pid);
457 int set_process_action(int argc, char **argv)
464 if ((pid = atoi(argv[0])) < 0)
467 set_enhance_pid(pid);
471 int set_process_group_action(int argc, char **argv)
478 if ((pid = atoi(argv[0])) < 0)
481 if (strncmp(argv[1], PROCESS_VIP, strlen(PROCESS_VIP)) == 0)
482 ret = device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_VIP, pid);
483 else if (strncmp(argv[1], PROCESS_PERMANENT, strlen(PROCESS_PERMANENT)) == 0)
484 ret = device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_PNP, pid);
487 _I("%s : pid %d", argv[1], pid);
489 _E("fail to set %s : pid %d",argv[1], pid);
493 void check_siop_disable_process(int pid, char *default_name)
496 char exe_name[PATH_MAX];
500 if (get_oom_score_adj(pid, &oom_score_adj) < 0) {
501 _E("fail to get adj value of pid: %d (%d)", pid);
505 if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0) {
506 _E("fail to check cmdline: %d (%s)", pid, default_name);
510 if (strncmp(exe_name, default_name, strlen(default_name)) != 0) {
514 switch (oom_score_adj) {
515 case OOMADJ_FOREGRD_LOCKED:
516 case OOMADJ_FOREGRD_UNLOCKED:
517 siop_level_action(0);
518 vconf_set_int(VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE, 1);
520 case OOMADJ_BACKGRD_LOCKED:
521 case OOMADJ_BACKGRD_UNLOCKED:
523 vconf_set_int(VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE, 0);
528 static DBusMessage *dbus_proc_handler(E_DBus_Object *obj, DBusMessage *msg)
531 DBusMessageIter iter;
539 dbus_error_init(&err);
541 if (!dbus_message_get_args(msg, &err,
542 DBUS_TYPE_STRING, &type_str,
543 DBUS_TYPE_INT32, &argc,
544 DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
545 _E("there is no message");
551 _E("message is invalid!");
556 pid = get_edbus_sender_pid(msg);
557 if (kill(pid, 0) == -1) {
558 _E("%d process does not exist, dbus ignored!", pid);
563 if (strncmp(type_str, PREDEF_FOREGRD, strlen(PREDEF_FOREGRD)) == 0)
564 ret = set_process_action(argc, (char **)&argv);
565 else if (strncmp(type_str, PREDEF_BACKGRD, strlen(PREDEF_BACKGRD)) == 0)
566 ret = set_process_action(argc, (char **)&argv);
567 else if (strncmp(type_str, PREDEF_ACTIVE, strlen(PREDEF_ACTIVE)) == 0)
568 ret = set_active_action(argc, (char **)&argv);
569 else if (strncmp(type_str, PREDEF_INACTIVE, strlen(PREDEF_INACTIVE)) == 0)
570 ret = set_inactive_action(argc, (char **)&argv);
572 reply = dbus_message_new_method_return(msg);
573 dbus_message_iter_init_append(reply, &iter);
574 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
579 static DBusMessage *dbus_oom_handler(E_DBus_Object *obj, DBusMessage *msg)
582 DBusMessageIter iter;
590 dbus_error_init(&err);
592 if (!dbus_message_get_args(msg, &err,
593 DBUS_TYPE_STRING, &type_str,
594 DBUS_TYPE_INT32, &argc,
595 DBUS_TYPE_STRING, &argv[0],
596 DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
597 _E("there is no message");
603 _E("message is invalid!");
608 pid = get_edbus_sender_pid(msg);
609 if (kill(pid, 0) == -1) {
610 _E("%d process does not exist, dbus ignored!", pid);
615 if (strncmp(type_str, OOMADJ_SET, strlen(OOMADJ_SET)) == 0)
616 ret = set_oom_score_adj_action(argc, (char **)&argv);
617 else if (strncmp(type_str, PROCESS_GROUP_SET, strlen(PROCESS_GROUP_SET)) == 0)
618 ret = set_process_group_action(argc, (char **)&argv);
620 reply = dbus_message_new_method_return(msg);
621 dbus_message_iter_init_append(reply, &iter);
622 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
627 static DBusMessage *dbus_get_siop_level(E_DBus_Object *obj, DBusMessage *msg)
629 DBusMessageIter iter;
633 level = SIOP_VALUE(siop_domain, siop);
634 reply = dbus_message_new_method_return(msg);
635 dbus_message_iter_init_append(reply, &iter);
636 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &level);
640 static DBusMessage *dbus_get_rear_level(E_DBus_Object *obj, DBusMessage *msg)
642 DBusMessageIter iter;
646 level = REAR_VALUE(siop);
647 reply = dbus_message_new_method_return(msg);
648 dbus_message_iter_init_append(reply, &iter);
649 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &level);
653 static DBusMessage *dbus_set_siop_level(E_DBus_Object *obj, DBusMessage *msg)
656 DBusMessageIter iter;
661 dbus_error_init(&err);
663 if (!dbus_message_get_args(msg, &err,
664 DBUS_TYPE_STRING, &argv[0],
665 DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
666 _E("there is no message");
670 ret = siop_changed(2, (char **)&argv);
672 reply = dbus_message_new_method_return(msg);
673 dbus_message_iter_init_append(reply, &iter);
674 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
679 static void dbus_proc_oomadj_set_signal_handler(void *data, DBusMessage *msg)
689 dbus_error_init(&err);
691 if (!dbus_message_get_args(msg, &err,
692 DBUS_TYPE_STRING, &type_str,
693 DBUS_TYPE_INT32, &argc,
694 DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
695 _E("there is no message");
700 _E("message is invalid!");
704 pid = get_edbus_sender_pid(msg);
705 if (kill(pid, 0) == -1) {
706 _E("%d process does not exist, dbus ignored!", pid);
710 if (strncmp(type_str, PREDEF_FOREGRD, strlen(PREDEF_FOREGRD)) == 0)
711 ret = set_process_action(argc, (char **)&argv);
712 else if (strncmp(type_str, PREDEF_BACKGRD, strlen(PREDEF_BACKGRD)) == 0)
713 ret = set_process_action(argc, (char **)&argv);
714 else if (strncmp(type_str, PREDEF_ACTIVE, strlen(PREDEF_ACTIVE)) == 0)
715 ret = set_active_action(argc, (char **)&argv);
716 else if (strncmp(type_str, PREDEF_INACTIVE, strlen(PREDEF_INACTIVE)) == 0)
717 ret = set_inactive_action(argc, (char **)&argv);
720 _E("set_process_action error!");
724 static const struct edbus_method edbus_methods[] = {
725 { PREDEF_FOREGRD, "sis", "i", dbus_proc_handler },
726 { PREDEF_BACKGRD, "sis", "i", dbus_proc_handler },
727 { PREDEF_ACTIVE, "sis", "i", dbus_proc_handler },
728 { PREDEF_INACTIVE, "sis", "i", dbus_proc_handler },
729 { OOMADJ_SET, "siss", "i", dbus_oom_handler },
730 { PROCESS_GROUP_SET, "siss", "i", dbus_oom_handler },
731 { SIOP_LEVEL_GET, NULL, "i", dbus_get_siop_level },
732 { REAR_LEVEL_GET, NULL, "i", dbus_get_rear_level },
733 { SIOP_LEVEL_SET, "ss", "i", dbus_set_siop_level },
736 static int proc_booting_done(void *data)
738 register_action(SIOP_CHANGED, siop_changed, NULL, NULL);
739 if (vconf_notify_key_changed(VCONFKEY_PM_STATE, (void *)siop_mode_lcd, NULL) < 0)
740 _E("Vconf notify key chaneged failed: KEY(%s)", VCONFKEY_PM_STATE);
741 siop_mode_lcd(NULL, NULL);
744 static void process_init(void *data)
748 register_edbus_signal_handler(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
749 SIGNAL_NAME_OOMADJ_SET,
750 dbus_proc_oomadj_set_signal_handler);
752 ret = register_edbus_method(DEVICED_PATH_PROCESS, edbus_methods, ARRAY_SIZE(edbus_methods));
754 _E("fail to init edbus method(%d)", ret);
756 register_action(PREDEF_FOREGRD, set_process_action, NULL, NULL);
757 register_action(PREDEF_BACKGRD, set_process_action, NULL, NULL);
758 register_action(PREDEF_ACTIVE, set_active_action, NULL, NULL);
759 register_action(PREDEF_INACTIVE, set_inactive_action, NULL, NULL);
760 register_action(OOMADJ_SET, set_oom_score_adj_action, NULL, NULL);
761 register_action(PROCESS_GROUP_SET, set_process_group_action, NULL, NULL);
763 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, proc_booting_done);
766 static const struct device_ops process_device_ops = {
767 .priority = DEVICE_PRIORITY_NORMAL,
769 .init = process_init,
772 DEVICE_OPS_REGISTER(&process_device_ops)