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 <sys/statvfs.h>
30 #include "device-node.h"
32 #include "core/noti.h"
33 #include "core/queue.h"
34 #include "core/predefine.h"
35 #include "core/data.h"
36 #include "core/devices.h"
37 #include "core/common.h"
38 #include "core/edbus-handler.h"
39 #include "core/device-notifier.h"
41 #define MEMNOTIFY_NORMAL 0x0000
42 #define MEMNOTIFY_LOW 0xfaac
43 #define MEMNOTIFY_CRITICAL 0xdead
44 #define MEMNOTIFY_REBOOT 0xb00f
46 #define MEMORY_STATUS_USR_PATH "/opt/usr"
47 #define MEMORY_MAX_MEM_STR_LEN 30
48 #define MEMORY_KILOBYTE_VALUE 1024
49 #define MEMORY_MEGABYTE_VALUE 1048576
50 #define MEMORY_GIGABYTE_VALUE 1073741824
51 #define MEMORY_RESERVE_VALUE (100*MEMORY_MEGABYTE_VALUE)
52 #define MEMNOTI_WARNING_VALUE (5) // 5% under
53 #define MEMNOTI_CRITICAL_VALUE (0.1) // 0.1% under
54 #define MEMNOTI_CRITICAL_SIZE(val) ((val*MEMNOTI_CRITICAL_VALUE)/100)
55 #define MEMNOTI_FULL_SIZE (MEMORY_RESERVE_VALUE + MEMORY_MEGABYTE_VALUE)
57 #define SIGNAL_LOWMEM_STATE "ChangeState"
58 #define SIGNAL_LOWMEM_FULL "Full"
60 #define POPUP_KEY_MEMNOTI "_MEM_NOTI_"
61 #define POPUP_KEY_APPNAME "_APP_NAME_"
63 #define LOWMEM_POPUP_NAME "lowmem-syspopup"
65 #define MEMNOTI_TIMER_INTERVAL 5
66 #define MEM_TRIM_TIMER_INTERVAL 86400 /* 24 hour */
67 #define MEM_FSTRIM_PATH "/sbin/fstrim"
69 #define MEM_TRIM_START_TIME 2 // AM 02:00:00
71 #define HOUR_SEC (MIN_SEC * MIN_SEC)
76 MEMNOTI_LEVEL_CRITICAL = 0,
77 MEMNOTI_LEVEL_WARNING,
87 static Ecore_Fd_Handler *lowmem_efd = NULL;
89 static int cur_mem_state = MEMNOTIFY_NORMAL;
91 static Ecore_Timer *memnoti_timer = NULL;
92 static Ecore_Timer *mem_trim_timer = NULL;
94 static double memnoti_warning_level = MEMNOTI_WARNING_VALUE;
95 static double memnoti_critical_level = MEMNOTI_CRITICAL_VALUE;
96 static double memnoti_full_level;
98 static void memnoti_send_broadcast(int status)
108 snprintf(str_status, sizeof(str_status), "%d", status);
110 broadcast_edbus_signal(DEVICED_PATH_LOWMEM, DEVICED_INTERFACE_LOWMEM,
111 SIGNAL_LOWMEM_STATE, "i", arr);
114 static void memnoti_level_broadcast(enum memnoti_level level)
116 static int status = 0;
117 if (level == MEMNOTI_LEVEL_CRITICAL && status == 0)
119 else if (level != MEMNOTI_LEVEL_CRITICAL && status == 1)
123 _D("send user mem noti : %d %d", level, status);
124 memnoti_send_broadcast(status);
127 static int memnoti_popup(enum memnoti_level level)
132 struct popup_data *params;
133 static const struct device_ops *apps = NULL;
135 if (level != MEMNOTI_LEVEL_WARNING && level != MEMNOTI_LEVEL_CRITICAL) {
136 _E("level check error : %d",level);
140 if (level == MEMNOTI_LEVEL_WARNING) {
142 } else if (level == MEMNOTI_LEVEL_CRITICAL) {
146 ret = vconf_get_int(VCONFKEY_STARTER_SEQUENCE, &val);
147 if (val == 0 || ret != 0)
150 apps = find_device("apps");
154 params = malloc(sizeof(struct popup_data));
155 if (params == NULL) {
159 params->name = LOWMEM_POPUP_NAME;
160 params->key = POPUP_KEY_MEMNOTI;
161 params->value = strdup(value);
162 apps->init((void *)params);
169 static enum memnoti_level check_memnoti_level(double total, double avail)
171 double tmp_size = (avail/total)*100;
173 if (tmp_size > memnoti_warning_level)
174 return MEMNOTI_LEVEL_NORMAL;
175 if (tmp_size > memnoti_critical_level)
176 return MEMNOTI_LEVEL_WARNING;
177 return MEMNOTI_LEVEL_CRITICAL;
180 static void memnoti_full_broadcast(double total, double avail)
182 static int status = 0;
184 double tmp_size = (avail/total)*100;
189 if (tmp_size <= memnoti_full_level && status == 0)
191 else if (tmp_size > memnoti_full_level && status == 1)
196 _D("send memory full noti : %d (total: %4.4lf avail: %4.4lf)", status, total, avail);
197 snprintf(str_status, sizeof(str_status), "%d", status);
199 broadcast_edbus_signal(DEVICED_PATH_LOWMEM, DEVICED_INTERFACE_LOWMEM,
200 SIGNAL_LOWMEM_FULL, "i", arr);
203 static int __fs_stat(double* pdTotal, double* pdAvail, const char* szPath)
208 if (NULL == pdAvail) {
209 _E("input param error");
213 if (!statvfs(szPath, &s)) {
214 reserved = MEMORY_RESERVE_VALUE/s.f_bsize;
215 if (s.f_bavail < reserved)
218 s.f_bavail -= reserved;
219 *pdTotal = (double)s.f_frsize * s.f_blocks;
220 *pdAvail = (double)s.f_bsize * s.f_bavail;
222 _E("fail to get memory size");
229 static void memory_status_set_full_mem_size(void)
234 if (__fs_stat(&dTotal, &dAvail, MEMORY_STATUS_USR_PATH) == 0) {
235 _E("fail to get mem size of %s",MEMORY_STATUS_USR_PATH);
239 memnoti_full_level = (MEMNOTI_FULL_SIZE/dTotal)*100;
240 _I("memnoti_full_level : %4.4lf(%d)", memnoti_full_level, MEMNOTI_FULL_SIZE);
243 static Eina_Bool memory_status_get_available_size(void *data)
245 static enum memnoti_level old = MEMNOTI_LEVEL_NORMAL;
246 enum memnoti_level now;
251 ret = __fs_stat(&dTotal, &dAvail, MEMORY_STATUS_USR_PATH);
253 _E("fail to get mem size of %s",MEMORY_STATUS_USR_PATH);
257 memnoti_full_broadcast(dTotal, dAvail);
259 now = check_memnoti_level(dTotal, dAvail);
261 memnoti_level_broadcast(now);
263 if (now < MEMNOTI_LEVEL_NORMAL && now < old) {
264 ret = memnoti_popup(now);
266 now = MEMNOTI_LEVEL_NORMAL;
270 ecore_timer_interval_set(memnoti_timer, MEMNOTI_TIMER_INTERVAL);
275 static int __memnoti_fd_init(struct main_data *ad)
277 memory_status_set_full_mem_size();
278 memory_status_get_available_size(ad);
279 memnoti_timer = ecore_timer_add(MEMNOTI_TIMER_INTERVAL,
280 memory_status_get_available_size, ad);
281 if (memnoti_timer == NULL)
282 _E("fail mem available noti timer add");
286 static Eina_Bool memory_trim_cb(void *data)
288 ecore_timer_interval_set(memnoti_timer, MEM_TRIM_TIMER_INTERVAL);
289 if (launch_if_noexist(MEM_FSTRIM_PATH, MEMORY_STATUS_USR_PATH) == -1) {
290 _E("fail to launch fstrim");
292 _D("fs memory trim is operated");
297 static int __mem_trim_delta(struct tm *cur_tm)
302 if (cur_tm->tm_hour < MEM_TRIM_START_TIME)
306 delta += ((sign_val) * (MEM_TRIM_START_TIME - cur_tm->tm_hour) * HOUR_SEC);
307 delta -= ((sign_val) * (cur_tm->tm_min * MIN_SEC + cur_tm->tm_sec));
311 static int __run_mem_trim(void)
318 cur_tm = (struct tm *)malloc(sizeof(struct tm));
319 if (cur_tm == NULL) {
320 _E("Fail to memory allocation");
324 if (localtime_r(&now, cur_tm) == NULL) {
325 _E("Fail to get localtime");
330 mem_trim_time = MEM_TRIM_TIMER_INTERVAL + __mem_trim_delta(cur_tm);
331 _D("start mem trim timer", mem_trim_time);
332 mem_trim_timer = ecore_timer_add(mem_trim_time, memory_trim_cb, NULL);
333 if (mem_trim_timer == NULL) {
334 _E("Fail to add mem trim timer");
342 static DBusMessage *edbus_getstatus(E_DBus_Object *obj, DBusMessage *msg)
344 DBusMessageIter iter;
350 ret = __fs_stat(&dTotal, &dAvail, MEMORY_STATUS_USR_PATH);
352 reply = dbus_message_new_method_return(msg);
353 dbus_message_iter_init_append(reply, &iter);
354 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &dTotal);
355 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &dAvail);
359 static DBusMessage *edbus_memtrim(E_DBus_Object *obj, DBusMessage *msg)
361 DBusMessageIter iter;
365 ret = launch_if_noexist(MEM_FSTRIM_PATH, MEMORY_STATUS_USR_PATH);
367 _E("fail to launch fstrim");
369 _D("fs memory trim is operated");
372 reply = dbus_message_new_method_return(msg);
373 dbus_message_iter_init_append(reply, &iter);
374 dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
378 static const struct edbus_method edbus_methods[] = {
379 { "getstorage", NULL, "i", edbus_getstatus },
380 { "MemTrim", NULL, "i", edbus_memtrim },
381 /* Add methods here */
384 static int booting_done(void *data)
392 if (__memnoti_fd_init(NULL) == -1)
393 _E("fail remain mem noti control fd init");
398 static int lowmem_poweroff(void *data)
401 ecore_timer_del(memnoti_timer);
402 memnoti_timer = NULL;
404 if (mem_trim_timer) {
405 ecore_timer_del(mem_trim_timer);
406 mem_trim_timer = NULL;
411 static void lowmem_init(void *data)
413 struct main_data *ad = (struct main_data*)data;
415 register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
416 register_notifier(DEVICE_NOTIFIER_POWEROFF, lowmem_poweroff);
417 ret = register_edbus_method(DEVICED_PATH_STORAGE, edbus_methods, ARRAY_SIZE(edbus_methods));
419 _E("fail to init edbus method(%d)", ret);
421 if (__run_mem_trim() < 0) {
422 _E("fail mem trim timer start");
426 static void lowmem_exit(void *data)
428 unregister_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
429 unregister_notifier(DEVICE_NOTIFIER_POWEROFF, lowmem_poweroff);
432 static const struct device_ops lowmem_device_ops = {
433 .priority = DEVICE_PRIORITY_NORMAL,
439 DEVICE_OPS_REGISTER(&lowmem_device_ops)