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>
34 #include "core/common.h"
35 #include "core/devices.h"
36 #include "core/device-notifier.h"
37 #include "display/enhance.h"
38 #include "proc-handler.h"
39 #include "core/edbus-handler.h"
41 #define TEMPERATURE_DBUS_INTERFACE "org.tizen.trm.siop"
42 #define TEMPERATURE_DBUS_PATH "/Org/Tizen/Trm/Siop"
43 #define TEMPERATURE_DBUS_SIGNAL "ChangedTemperature"
45 #define LIMITED_PROCESS_OOMADJ 15
47 #define PROCESS_VIP "process_vip"
48 #define PROCESS_PERMANENT "process_permanent"
49 #define OOMADJ_SET "oomadj_set"
51 #define PREDEF_BACKGRD "backgrd"
52 #define PREDEF_FOREGRD "foregrd"
53 #define PREDEF_ACTIVE "active"
54 #define PREDEF_INACTIVE "inactive"
55 #define PROCESS_GROUP_SET "process_group_set"
57 #define VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE "memory/private/sysman/siop_disable"
60 #define SIOP_CTRL_LEVEL_MASK 0xFFFF
61 #define SIOP_CTRL_LEVEL(val) ((val & SIOP_CTRL_LEVEL_MASK) << 16)
62 #define SIOP_CTRL_VALUE(s, r) (s | (r << 4))
63 #define SIOP_VALUE(d, val) ((d) * (val & 0xF))
64 #define REAR_VALUE(val) (val >> 4)
66 #define SIGNAL_SIOP_CHANGED "ChangedSiop"
67 #define SIGNAL_REAR_CHANGED "ChangedRear"
68 #define SIOP_LEVEL_GET "GetSiopLevel"
69 #define REAR_LEVEL_GET "GetRearLevel"
70 #define SIOP_LEVEL_SET "SetSiopLevel"
72 #define SIGNAL_NAME_OOMADJ_SET "OomadjSet"
74 enum SIOP_DOMAIN_TYPE {
86 static int siop_domain = SIOP_POSITIVE;
93 typedef struct _node {
98 static Node *head = NULL;
100 static Node *find_node(pid_t pid)
112 static Node *add_node(pid_t pid)
116 n = (Node *) malloc(sizeof(Node));
118 _E("Not enough memory, add cond. fail");
129 static int del_node(Node *n)
142 prev->next = t->next;
155 int cur_siop_level(void)
157 return SIOP_VALUE(siop_domain, siop);
160 static void siop_level_action(int level)
162 int val = SIOP_CTRL_LEVEL(level);
164 static int siop_level = 0;
165 static int rear_level = 0;
166 static int initialized = 0;
167 static int domain = 0;
171 if (initialized && siop == level && mode == old && domain == siop_domain)
175 domain = siop_domain;
176 if (siop_domain == SIOP_NEGATIVE)
181 device_set_property(DEVICE_TYPE_POWER, PROP_POWER_SIOP_CONTROL, val);
183 val = SIOP_VALUE(siop_domain, level);
184 if (siop_level != val) {
186 snprintf(str_level, sizeof(str_level), "%d", siop_level);
188 _I("broadcast siop %s", str_level);
189 broadcast_edbus_signal(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
190 SIGNAL_SIOP_CHANGED, "i", arr);
193 val = REAR_VALUE(level);
194 if (rear_level != val) {
196 snprintf(str_level, sizeof(str_level), "%d", rear_level);
198 _I("broadcast rear %s", str_level);
199 broadcast_edbus_signal(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
200 SIGNAL_REAR_CHANGED, "i", arr);
202 _I("level is d:%d(0x%x) s:%d r:%d", siop_domain, siop, siop_level, rear_level);
205 static int siop_changed(int argc, char **argv)
213 if (argc != 2 || argv[0] == NULL) {
214 _E("fail to check value");
221 level = atoi(argv[0]);
222 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_ELVSS_CONTROL, level);
223 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_SIOP_LEVEL, &level);
227 if (level <= SIOP_NEGATIVE)
228 siop_domain = SIOP_NEGATIVE;
230 siop_domain = SIOP_POSITIVE;
231 siop_level = siop_domain * level;
237 level = atoi(argv[1]);
238 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_REAR_LEVEL, &level) == 0)
242 level = SIOP_CTRL_VALUE(siop_level, rear_level);
243 siop_level_action(level);
247 static int siop_mode_lcd(keynode_t *key_nodes, void *data)
250 if (vconf_get_int(VCONFKEY_PM_STATE, &pm_state) != 0)
251 _E("Fail to get vconf value for pm state\n");
252 if (pm_state == VCONFKEY_PM_STATE_LCDOFF)
256 siop_level_action(siop);
260 static void memcg_move_group(int pid, int oom_score_adj)
265 char exe_name[PATH_MAX];
267 if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0) {
268 _E("fail to get process name(%d)", pid);
272 _SD("memcg_move_group : %s, pid = %d", exe_name, pid);
273 if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED)
274 sprintf(buf, "/sys/fs/cgroup/memory/background/cgroup.procs");
275 else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED && oom_score_adj < OOMADJ_BACKGRD_LOCKED)
276 sprintf(buf, "/sys/fs/cgroup/memory/foreground/cgroup.procs");
283 size = sprintf(buf, "%d", pid);
284 if (fwrite(buf, size, 1, f) != 1)
285 _E("fwrite cgroup tasks : %d\n", pid);;
289 int get_oom_score_adj(int pid, int *oom_score_adj)
297 fp = open_proc_oom_score_adj_file(pid, "r");
300 if (fgets(buf, PATH_MAX, fp) == NULL) {
305 *oom_score_adj = atoi(buf);
310 int set_oom_score_adj(pid_t pid, int new_oom_score_adj)
313 int old_oom_score_adj;
314 char exe_name[PATH_MAX];
316 if (get_cmdline_name(pid, exe_name, PATH_MAX) < 0)
317 snprintf(exe_name, sizeof(exe_name), "Unknown (maybe dead)");
319 if (get_oom_score_adj(pid, &old_oom_score_adj) < 0)
322 _SI("Process %s, pid %d, old_oom_score_adj %d new_oom_score_adj %d",
323 exe_name, pid, old_oom_score_adj, new_oom_score_adj);
325 if (new_oom_score_adj < OOMADJ_SU)
326 new_oom_score_adj = OOMADJ_SU;
328 fp = open_proc_oom_score_adj_file(pid, "w");
332 fprintf(fp, "%d", new_oom_score_adj);
338 int set_su_oom_score_adj(pid_t pid)
340 return set_oom_score_adj(pid, OOMADJ_SU);
343 int check_oom_score_adj(int oom_score_adj)
345 if (oom_score_adj != OOMADJ_FOREGRD_LOCKED && oom_score_adj != OOMADJ_FOREGRD_UNLOCKED)
350 int set_oom_score_adj_action(int argc, char **argv)
354 int new_oom_score_adj = 0;
358 if ((pid = atoi(argv[0])) < 0 || (new_oom_score_adj = atoi(argv[1])) <= -20)
361 _I("OOMADJ_SET : pid %d, new_oom_score_adj %d", pid, new_oom_score_adj);
363 fp = open_proc_oom_score_adj_file(pid, "w");
366 if (new_oom_score_adj < OOMADJ_SU)
367 new_oom_score_adj = OOMADJ_SU;
368 fprintf(fp, "%d", new_oom_score_adj);
371 memcg_move_group(pid, new_oom_score_adj);
375 int set_active_action(int argc, char **argv)
379 int oom_score_adj = 0;
383 if ((pid = atoi(argv[0])) < 0)
386 if (get_oom_score_adj(pid, &oom_score_adj) < 0)
389 switch (oom_score_adj) {
390 case OOMADJ_FOREGRD_LOCKED:
391 case OOMADJ_BACKGRD_LOCKED:
395 case OOMADJ_FOREGRD_UNLOCKED:
396 ret = set_oom_score_adj((pid_t) pid, OOMADJ_FOREGRD_LOCKED);
398 case OOMADJ_BACKGRD_UNLOCKED:
399 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
402 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
405 if(oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
406 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_LOCKED);
408 _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
413 set_enhance_pid(pid);
417 int set_inactive_action(int argc, char **argv)
421 int oom_score_adj = 0;
425 if ((pid = atoi(argv[0])) < 0)
428 if (get_oom_score_adj(pid, &oom_score_adj) < 0)
431 switch (oom_score_adj) {
432 case OOMADJ_FOREGRD_UNLOCKED:
433 case OOMADJ_BACKGRD_UNLOCKED:
437 case OOMADJ_FOREGRD_LOCKED:
438 ret = set_oom_score_adj((pid_t) pid, OOMADJ_FOREGRD_UNLOCKED);
440 case OOMADJ_BACKGRD_LOCKED:
441 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
444 ret = set_oom_score_adj((pid_t) pid, OOMADJ_BACKGRD_UNLOCKED);
447 if(oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
450 _E("Unknown oom_score_adj value (%d) !", oom_score_adj);
456 set_enhance_pid(pid);
460 int set_process_action(int argc, char **argv)
467 if ((pid = atoi(argv[0])) < 0)
470 set_enhance_pid(pid);
474 int set_process_group_action(int argc, char **argv)
481 if ((pid = atoi(argv[0])) < 0)
484 if (strncmp(argv[1], PROCESS_VIP, strlen(PROCESS_VIP)) == 0)
485 ret = device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_VIP, pid);
486 else if (strncmp(argv[1], PROCESS_PERMANENT, strlen(PROCESS_PERMANENT)) == 0)
487 ret = device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_PNP, pid);
490 _I("%s : pid %d", argv[1], pid);
492 _E("fail to set %s : pid %d",argv[1], pid);
496 void check_siop_disable_process(int pid, char *default_name)
499 char exe_name[PATH_MAX];
503 if (get_oom_score_adj(pid, &oom_score_adj) < 0) {
504 _E("fail to get adj value of pid: %d (%d)", pid);
508 if (get_cmdline_name(pid, exe_name, PATH_MAX) != 0) {
509 _E("fail to check cmdline: %d (%s)", pid, default_name);
513 if (strncmp(exe_name, default_name, strlen(default_name)) != 0) {
517 switch (oom_score_adj) {
518 case OOMADJ_FOREGRD_LOCKED:
519 case OOMADJ_FOREGRD_UNLOCKED:
520 siop_level_action(0);
521 vconf_set_int(VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE, 1);
523 case OOMADJ_BACKGRD_LOCKED:
524 case OOMADJ_BACKGRD_UNLOCKED:
526 vconf_set_int(VCONFKEY_INTERNAL_PRIVATE_SIOP_DISABLE, 0);
531 static DBusMessage *dbus_proc_handler(E_DBus_Object *obj, DBusMessage *msg)
534 DBusMessageIter iter;
542 dbus_error_init(&err);
544 if (!dbus_message_get_args(msg, &err,
545 DBUS_TYPE_STRING, &type_str,
546 DBUS_TYPE_INT32, &argc,
547 DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
548 _E("there is no message");
554 _E("message is invalid!");
559 pid = get_edbus_sender_pid(msg);
560 if (kill(pid, 0) == -1) {
561 _E("%d process does not exist, dbus ignored!", pid);
566 if (strncmp(type_str, PREDEF_FOREGRD, strlen(PREDEF_FOREGRD)) == 0)
567 ret = set_process_action(argc, (char **)&argv);
568 else if (strncmp(type_str, PREDEF_BACKGRD, strlen(PREDEF_BACKGRD)) == 0)
569 ret = set_process_action(argc, (char **)&argv);
570 else if (strncmp(type_str, PREDEF_ACTIVE, strlen(PREDEF_ACTIVE)) == 0)
571 ret = set_active_action(argc, (char **)&argv);
572 else if (strncmp(type_str, PREDEF_INACTIVE, strlen(PREDEF_INACTIVE)) == 0)
573 ret = set_inactive_action(argc, (char **)&argv);
575 reply = dbus_message_new_method_return(msg);
576 dbus_message_iter_init_append(reply, &iter);
577 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
582 static DBusMessage *dbus_oom_handler(E_DBus_Object *obj, DBusMessage *msg)
585 DBusMessageIter iter;
593 dbus_error_init(&err);
595 if (!dbus_message_get_args(msg, &err,
596 DBUS_TYPE_STRING, &type_str,
597 DBUS_TYPE_INT32, &argc,
598 DBUS_TYPE_STRING, &argv[0],
599 DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
600 _E("there is no message");
606 _E("message is invalid!");
611 pid = get_edbus_sender_pid(msg);
612 if (kill(pid, 0) == -1) {
613 _E("%d process does not exist, dbus ignored!", pid);
618 if (strncmp(type_str, OOMADJ_SET, strlen(OOMADJ_SET)) == 0)
619 ret = set_oom_score_adj_action(argc, (char **)&argv);
620 else if (strncmp(type_str, PROCESS_GROUP_SET, strlen(PROCESS_GROUP_SET)) == 0)
621 ret = set_process_group_action(argc, (char **)&argv);
623 reply = dbus_message_new_method_return(msg);
624 dbus_message_iter_init_append(reply, &iter);
625 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
630 static DBusMessage *dbus_get_siop_level(E_DBus_Object *obj, DBusMessage *msg)
632 DBusMessageIter iter;
636 level = SIOP_VALUE(siop_domain, siop);
637 reply = dbus_message_new_method_return(msg);
638 dbus_message_iter_init_append(reply, &iter);
639 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &level);
643 static DBusMessage *dbus_get_rear_level(E_DBus_Object *obj, DBusMessage *msg)
645 DBusMessageIter iter;
649 level = REAR_VALUE(siop);
650 reply = dbus_message_new_method_return(msg);
651 dbus_message_iter_init_append(reply, &iter);
652 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &level);
656 static DBusMessage *dbus_set_siop_level(E_DBus_Object *obj, DBusMessage *msg)
659 DBusMessageIter iter;
664 dbus_error_init(&err);
666 if (!dbus_message_get_args(msg, &err,
667 DBUS_TYPE_STRING, &argv[0],
668 DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
669 _E("there is no message");
673 ret = siop_changed(2, (char **)&argv);
675 reply = dbus_message_new_method_return(msg);
676 dbus_message_iter_init_append(reply, &iter);
677 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
682 static void dbus_proc_oomadj_set_signal_handler(void *data, DBusMessage *msg)
692 dbus_error_init(&err);
694 if (!dbus_message_get_args(msg, &err,
695 DBUS_TYPE_STRING, &type_str,
696 DBUS_TYPE_INT32, &argc,
697 DBUS_TYPE_STRING, &argv, DBUS_TYPE_INVALID)) {
698 _E("there is no message");
703 _E("message is invalid!");
707 pid = get_edbus_sender_pid(msg);
708 if (kill(pid, 0) == -1) {
709 _E("%d process does not exist, dbus ignored!", pid);
713 if (strncmp(type_str, PREDEF_FOREGRD, strlen(PREDEF_FOREGRD)) == 0)
714 ret = set_process_action(argc, (char **)&argv);
715 else if (strncmp(type_str, PREDEF_BACKGRD, strlen(PREDEF_BACKGRD)) == 0)
716 ret = set_process_action(argc, (char **)&argv);
717 else if (strncmp(type_str, PREDEF_ACTIVE, strlen(PREDEF_ACTIVE)) == 0)
718 ret = set_active_action(argc, (char **)&argv);
719 else if (strncmp(type_str, PREDEF_INACTIVE, strlen(PREDEF_INACTIVE)) == 0)
720 ret = set_inactive_action(argc, (char **)&argv);
723 _E("set_process_action error!");
726 static const struct edbus_method edbus_methods[] = {
727 { PREDEF_FOREGRD, "sis", "i", dbus_proc_handler },
728 { PREDEF_BACKGRD, "sis", "i", dbus_proc_handler },
729 { PREDEF_ACTIVE, "sis", "i", dbus_proc_handler },
730 { PREDEF_INACTIVE, "sis", "i", dbus_proc_handler },
731 { OOMADJ_SET, "siss", "i", dbus_oom_handler },
732 { PROCESS_GROUP_SET, "siss", "i", dbus_oom_handler },
733 { SIOP_LEVEL_GET, NULL, "i", dbus_get_siop_level },
734 { REAR_LEVEL_GET, NULL, "i", dbus_get_rear_level },
735 { SIOP_LEVEL_SET, "ss", "i", dbus_set_siop_level },
738 static int proc_booting_done(void *data)
745 if (vconf_notify_key_changed(VCONFKEY_PM_STATE, (void *)siop_mode_lcd, NULL) < 0)
746 _E("Vconf notify key chaneged failed: KEY(%s)", VCONFKEY_PM_STATE);
747 siop_mode_lcd(NULL, NULL);
752 static int process_execute(void *data)
754 struct siop_data* key_data = (struct siop_data *)data;
762 booting_done = proc_booting_done(NULL);
766 if (key_data == NULL)
769 level = key_data->siop;
770 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_ELVSS_CONTROL, level);
771 ret = device_get_property(DEVICE_TYPE_POWER, PROP_POWER_SIOP_LEVEL, &level);
775 if (level <= SIOP_NEGATIVE)
776 siop_domain = SIOP_NEGATIVE;
778 siop_domain = SIOP_POSITIVE;
779 siop_level = siop_domain * level;
782 level = key_data->rear;
783 if (device_get_property(DEVICE_TYPE_POWER, PROP_POWER_REAR_LEVEL, &level) == 0)
787 level = SIOP_CTRL_VALUE(siop_level, rear_level);
788 siop_level_action(level);
792 static void temp_change_signal_handler(void *data, DBusMessage *msg)
797 if (dbus_message_is_signal(msg, TEMPERATURE_DBUS_INTERFACE, TEMPERATURE_DBUS_SIGNAL) == 0) {
798 _E("there is no cool down signal");
802 dbus_error_init(&err);
804 if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &level, DBUS_TYPE_INVALID) == 0) {
805 _E("there is no message");
809 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_ELVSS_CONTROL, level);
812 static void process_init(void *data)
816 register_edbus_signal_handler(DEVICED_PATH_PROCESS, DEVICED_INTERFACE_PROCESS,
817 SIGNAL_NAME_OOMADJ_SET,
818 dbus_proc_oomadj_set_signal_handler);
819 register_edbus_signal_handler(TEMPERATURE_DBUS_PATH, TEMPERATURE_DBUS_INTERFACE,
820 TEMPERATURE_DBUS_SIGNAL,
821 temp_change_signal_handler);
823 ret = register_edbus_method(DEVICED_PATH_PROCESS, edbus_methods, ARRAY_SIZE(edbus_methods));
825 _E("fail to init edbus method(%d)", ret);
827 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, proc_booting_done);
830 static const struct device_ops process_device_ops = {
831 .priority = DEVICE_PRIORITY_NORMAL,
832 .name = PROC_OPS_NAME,
833 .init = process_init,
834 .execute = process_execute,
837 DEVICE_OPS_REGISTER(&process_device_ops)