d650ff59e1ceec49d324f84278f00ab15f2ab522
[framework/system/system-server.git] / ss_lowmem_handler.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.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.tizenopensource.org/license
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
18 #include <fcntl.h>
19 #include <assert.h>
20 #include <limits.h>
21 #include <sysman.h>
22 #include <heynoti.h>
23 #include <vconf.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/shm.h>
27
28 #include "ss_device_plugin.h"
29 #include "ss_log.h"
30 #include "ss_noti.h"
31 #include "ss_queue.h"
32 #include "include/ss_data.h"
33
34 #define DELETE_SM               "sh -c "PREFIX"/bin/delete.sm"
35
36 #define MEMNOTIFY_NORMAL        0x0000
37 #define MEMNOTIFY_LOW           0xfaac
38 #define MEMNOTIFY_CRITICAL      0xdead
39 #define MEMNOTIFY_REBOOT        0xb00f
40
41 #define _SYS_RES_CLEANUP        "RES_CLEANUP"
42
43 #define MEM_THRESHOLD_LV1       60
44 #define MEM_THRESHOLD_LV2       40
45
46
47 struct lowmem_process_entry {
48         unsigned cur_mem_state;
49         unsigned new_mem_state;
50         int (*action) (void *);
51 };
52
53 static int lowmem_fd = -1;
54 static int cur_mem_state = MEMNOTIFY_NORMAL;
55
56 Ecore_Timer *oom_timer;
57 #define OOM_TIMER_INTERVAL      5
58
59 static int memory_low_act(void *ad);
60 static int memory_oom_act(void *ad);
61 static int memory_normal_act(void *ad);
62
63 static struct lowmem_process_entry lpe[] = {
64         {MEMNOTIFY_NORMAL, MEMNOTIFY_LOW, memory_low_act},
65         {MEMNOTIFY_NORMAL, MEMNOTIFY_CRITICAL, memory_oom_act},
66         {MEMNOTIFY_LOW, MEMNOTIFY_CRITICAL, memory_oom_act},
67         {MEMNOTIFY_CRITICAL, MEMNOTIFY_CRITICAL, memory_oom_act},
68         {MEMNOTIFY_LOW, MEMNOTIFY_NORMAL, memory_normal_act},
69         {MEMNOTIFY_CRITICAL, MEMNOTIFY_NORMAL, memory_normal_act},
70
71 };
72
73 unsigned int oom_delete_sm_time = 0;
74
75 static int remove_shm()
76 {
77         int maxid, shmid, id;
78         struct shmid_ds shmseg;
79         struct shm_info shm_info;
80
81         maxid = shmctl(0, SHM_INFO, (struct shmid_ds *)(void *)&shm_info);
82         if (maxid < 0) {
83                 PRT_TRACE_ERR("shared mem error\n");
84                 return -1;
85         }
86
87         for (id = 0; id <= maxid; id++) {
88                 shmid = shmctl(id, SHM_STAT, &shmseg);
89                 if (shmid < 0)
90                         continue;
91                 if (shmseg.shm_nattch == 0) {
92                         PRT_TRACE("shared memory killer ==> %d killed\n",
93                                   shmid);
94                         shmctl(shmid, IPC_RMID, NULL);
95                 }
96         }
97         return 0;
98 }
99
100 static char *convert_to_str(unsigned int mem_state)
101 {
102         char *tmp;
103         switch (mem_state) {
104         case MEMNOTIFY_NORMAL:
105                 tmp = "mem normal";
106                 break;
107         case MEMNOTIFY_LOW:
108                 tmp = "mem low";
109                 break;
110         case MEMNOTIFY_CRITICAL:
111                 tmp = "mem critical";
112                 break;
113         case MEMNOTIFY_REBOOT:
114                 tmp = "mem reboot";
115                 break;
116         default:
117                 assert(0);
118         }
119         return tmp;
120 }
121
122 static void print_lowmem_state(unsigned int mem_state)
123 {
124         PRT_TRACE("[LOW MEM STATE] %s ==> %s", convert_to_str(cur_mem_state),
125                   convert_to_str(mem_state));
126 }
127
128 static int memory_low_act(void *data)
129 {
130         char lowmem_noti_name[NAME_MAX];
131
132         PRT_TRACE("[LOW MEM STATE] memory low state");
133         remove_shm();
134
135         heynoti_get_snoti_name(_SYS_RES_CLEANUP, lowmem_noti_name, NAME_MAX);
136         ss_noti_send(lowmem_noti_name);
137         vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
138                       VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING);
139                 
140         ss_action_entry_call_internal(PREDEF_LOWMEM, 1, LOW_MEM_ACT);
141
142         return 0;
143 }
144
145 static int memory_oom_act(void *data)
146 {
147         unsigned int cur_time;
148         char lowmem_noti_name[NAME_MAX];
149
150         PRT_TRACE("[LOW MEM STATE] memory oom state");
151         cur_time = time(NULL);
152         PRT_TRACE("cur=%d, old=%d, cur-old=%d", cur_time, oom_delete_sm_time,
153                   cur_time - oom_delete_sm_time);
154         if (cur_time - oom_delete_sm_time > 15) {
155                 remove_shm();
156                 oom_delete_sm_time = cur_time;
157                 /* Also clean up unreturned memory of applications */
158                 heynoti_get_snoti_name(_SYS_RES_CLEANUP, lowmem_noti_name,
159                                        NAME_MAX);
160                 ss_noti_send(lowmem_noti_name);
161         }
162         vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
163                       VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
164
165         ss_action_entry_call_internal(PREDEF_LOWMEM, 1, OOM_MEM_ACT);
166
167         return 1;
168 }
169
170 static int memory_normal_act(void *data)
171 {
172         PRT_TRACE("[LOW MEM STATE] memory normal state");
173         vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
174                       VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
175         return 0;
176 }
177
178 static int lowmem_process(unsigned int mem_state, void *ad)
179 {
180         int i;
181         for (i = 0; i < sizeof(lpe) / sizeof(struct lowmem_process_entry); i++) {
182                 if ((cur_mem_state == lpe[i].cur_mem_state)
183                     && (mem_state == lpe[i].new_mem_state)) {
184
185                         if(oom_timer != NULL) {
186                                 ecore_timer_del(oom_timer);
187                                 oom_timer = NULL;
188                         }
189                         lpe[i].action(ad);
190                         if(mem_state == MEMNOTIFY_CRITICAL) 
191                                 oom_timer = ecore_timer_add(OOM_TIMER_INTERVAL,lpe[i].action, ad);
192                         return 0;
193                 }
194         }
195         return 0;
196 }
197
198 static unsigned int lowmem_read(int fd)
199 {
200         unsigned int mem_state;
201         read(fd, &mem_state, sizeof(mem_state));
202         return mem_state;
203 }
204
205 static int lowmem_cb(void *data, Ecore_Fd_Handler * fd_handler)
206 {
207         int fd;
208         struct ss_main_data *ad = (struct ss_main_data *)data;
209         unsigned int mem_state;
210
211         if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
212                 PRT_TRACE_ERR
213                     ("ecore_main_fd_handler_active_get error , return\n");
214                 return 1;
215         }
216
217         fd = ecore_main_fd_handler_fd_get(fd_handler);
218
219         mem_state = lowmem_read(fd);
220         print_lowmem_state(mem_state);
221         lowmem_process(mem_state, ad);
222         cur_mem_state = mem_state;
223
224         return 1;
225 }
226
227 static int set_threshold()
228 {
229         if (0 > plugin_intf->OEM_sys_set_memnotify_threshold_lv1(MEM_THRESHOLD_LV1)) {
230                 PRT_TRACE_ERR("Set memnorify threshold lv1 failed");
231                 return -1;
232         }
233
234         if (0 > plugin_intf->OEM_sys_set_memnotify_threshold_lv2(MEM_THRESHOLD_LV2)) {
235                 PRT_TRACE_ERR("Set memnorify threshold lv2 failed");
236                 return -1;
237         }
238
239         return 0;
240 }
241
242 int ss_lowmem_init(struct ss_main_data *ad)
243 {
244         char lowmem_dev_node[PATH_MAX];
245
246         if (0 > plugin_intf->OEM_sys_get_memnotify_node(lowmem_dev_node)) {
247                 PRT_TRACE_ERR("Low memory handler fd init failed");
248                 return -1;
249         }
250
251         lowmem_fd = open(lowmem_dev_node, O_RDONLY);
252         if (lowmem_fd < 0) {
253                 PRT_TRACE_ERR("ss_lowmem_init fd open failed");
254                 return -1;
255         }
256
257         oom_timer=NULL;
258         ecore_main_fd_handler_add(lowmem_fd, ECORE_FD_READ, lowmem_cb, ad, NULL,
259                                   NULL);
260         if (set_threshold() < 0) {
261                 PRT_TRACE_ERR("Setting lowmem threshold is failed");
262                 return -1;
263         }
264
265         return 0;
266 }