Remove useless source code
[platform/core/system/resourced.git] / src / resource-limiter / memory / lowmem-limit.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18 */
19
20
21 #ifndef _GNU_SOURCE
22         /* For asprintf(3). Only affects this one file
23          * because tests dislike GNU_SOURCE since it
24          * makes mockability difficult. */
25         #define _GNU_SOURCE
26         #include <stdio.h>
27         #undef _GNU_SOURCE
28 #else
29         #include <stdio.h>
30 #endif
31
32 #include <sys/types.h>
33 #include <signal.h>
34 #include <unistd.h>
35
36 #include "trace.h"
37 #include "macro.h"
38 #include "module.h"
39 #include "module-data.h"
40 #include "lowmem-handler.h"
41 #include "notifier.h"
42 #include "procfs.h"
43 #include "cgroup.h"
44 #include "const.h"
45 #include "proc-common.h"
46 #include "memory-cgroup.h"
47 #include "util.h"
48 #include "smaps.h"
49 #include "config-parser.h"
50 #include "resourced-helper-worker.h"
51 #include "fd-handler.h"
52 #include "dbus-handler.h"
53 #include "safe-kill.h"
54
55 #define MEM_CONF_FILE                   RD_CONFIG_FILE(limiter)
56 #define MEMLIMIT_CONFIG_SECTION "MemLimit"
57 #define MEMLIMIT_CONFIG_TRIGGER "MemLimitTrigger"
58
59 #define MEMLIMIT_CONFIG_LIM_PFX MEMLIMIT_CONFIG_SECTION
60 #define MEMLIMIT_CONFIG_SERVICE MEMLIMIT_CONFIG_LIM_PFX "Service"
61 #define MEMLIMIT_CONFIG_GUIAPP  MEMLIMIT_CONFIG_LIM_PFX "GUIApp"
62 #define MEMLIMIT_CONFIG_WIDGET  MEMLIMIT_CONFIG_LIM_PFX "Widget"
63 #define MEMLIMIT_CONFIG_BGAPP   MEMLIMIT_CONFIG_LIM_PFX "BgApp"
64 #define MIN_LIMIT_VALUE         MBYTE_TO_BYTE(1) /* Byte */
65
66 enum mem_limit_type {
67         /* check only swap usage also */
68         MEM_LIMIT_NONE,
69         /* register OOM event and control application in kernel side */
70         MEM_LIMIT_OOM,
71         /* register threshold event and control application in resourced*/
72         MEM_LIMIT_TRHESHOLD,
73 };
74
75 static enum mem_limit_type mem_limit;
76
77
78 static GHashTable *memory_limit_hash;
79 static char *registerpath;
80 static unsigned int mem_service_limit;
81 static unsigned int mem_widget_limit;
82 static unsigned int mem_guiapp_limit;
83 static unsigned int mem_bgapp_limit;
84
85 static int mem_service_action = PROC_ACTION_KILL;
86 static int mem_widget_action = PROC_ACTION_KILL;
87 static int mem_guiapp_action = PROC_ACTION_KILL;
88 static int mem_bgapp_action = PROC_ACTION_KILL;
89
90 struct memory_info {
91         pid_t pid;
92         unsigned int size;
93 };
94
95 struct memory_limit_log {
96         pid_t pid;
97         char *appname;
98         char *cgdir;
99 };
100
101 static int get_pid_use_max_memory(GArray *pids_array, unsigned int *max_mem)
102 {
103         int i, ret;
104         struct memory_info mi = {0, 0};
105
106         if (!pids_array->len)
107                 return RESOURCED_ERROR_NO_DATA;
108
109         for (i = 0; i < pids_array->len; i++) {
110                 pid_t mpid = 0;
111                 unsigned int size;
112
113                 mpid = g_array_index(pids_array, pid_t, i);
114                 if (!mpid)
115                         continue;
116
117                 ret = proc_get_mem_usage(mpid, &size);
118                 if (ret != RESOURCED_ERROR_NONE)
119                         continue;
120
121                 _D("%d used %d memory", mpid, size);
122
123                 if (size > mi.size) {
124                         mi.pid = mpid;
125                         mi.size = size;
126                 }
127         }
128         *max_mem = mi.size;
129         _D("%d used max %d memory", mi.pid, mi.size);
130         return mi.pid;
131 }
132
133 static pid_t get_main_pid(const char *dir, unsigned int *max_mem)
134 {
135         GArray *pids_array = NULL;
136         _cleanup_free_ char *path = NULL;
137         int ret;
138         pid_t main_pid;
139
140         ret = asprintf(&path, "%s/", dir);
141         if (ret < 0)
142                 return -ENOMEM;
143
144         ret = cgroup_get_pids(path, &pids_array);
145         if (ret < 0 || !pids_array->len) {
146                 g_array_free(pids_array, true);
147                 return RESOURCED_ERROR_NO_DATA;
148         }
149
150         main_pid = get_pid_use_max_memory(pids_array, max_mem);
151         g_array_free(pids_array, true);
152         return main_pid;
153 }
154
155 static void memory_limit_hash_destroy(gpointer data)
156 {
157         struct memory_limit_event *mle = (struct memory_limit_event *)data;
158         if (!mle) {
159                 _E("[DEBUG] Memory limit event structure is NULL");
160                 return;
161         }
162
163         if (mle->fd > 0)
164                 close(mle->fd);
165
166         if (mle->path)
167                 free(mle->path);
168
169         /* NB: `mle->fdh` is NOT cleaned up here. This is because the removal
170          * of `memory_limit_event` only happens in two cases:
171          *
172          *  a) at the end of `lowmem_limit_cb`, which returns `false`
173          *     on removal, which results in `fd_handler` getting cleaned
174          *     up independently (see `channel_changed` in `fd-handler.c`)
175          *
176          *  b) at exit, by which time GIO channels should've already been
177          *     cleaned up (due to `g_main_loop_quit` et al.). */
178
179         free(mle);
180 }
181
182 static int lowmem_limit_broadcast(pid_t pid)
183 {
184         int ret;
185         char appname[PROC_NAME_MAX];
186         struct proc_app_info *pai = NULL;
187         char *appid;
188
189         pai = find_app_info(pid);
190         if (pai) {
191                 appid = pai->appid;
192         } else {
193                 ret = proc_get_cmdline(pid, appname, sizeof appname);
194                 if (ret < 0) {
195                         _E("[DEBUG] Failed to get cmdline basename of pid(%d)", pid);
196                         return ret;
197                 }
198                 appid = appname;
199         }
200
201         ret = d_bus_broadcast_signal_gvariant(RESOURCED_PATH_OOM,
202                         RESOURCED_INTERFACE_OOM, SIGNAL_OOM_MEMLIMIT_EVENT,
203                         g_variant_new("(is)", pid, appid));
204         if (ret < 0)
205                 _E("[DEBUG] Fail to broadcast dbus signal with pid(%d), appname(%s)", pid, appname);
206
207         return ret;
208 }
209
210 static gboolean liveness_check_cb(gpointer data)
211 {
212         struct memory_limit_event *mle = (struct memory_limit_event *)data;
213
214         if (!mle) {
215                 _E("[DEBUG] memory limit event structure is NULL");
216                 goto timer_out;
217         }
218
219         if (mle->pid <= 0) {
220                 _E("[DEBUG] pid should be larger than 0");
221                 goto mle_timer_init;
222         }
223
224         if (kill(mle->pid, 0) == 0) {
225                 safe_kill(mle->pid, SIGKILL);
226         }
227
228 mle_timer_init:
229         mle->pid = -1;
230 timer_out:
231         return G_SOURCE_REMOVE;
232 }
233
234 static bool memory_action_cb(int fd, void *data)
235 {
236         int result;
237         pid_t main_pid;
238         uint32_t usage, max_mem;
239         uint64_t dummy_efd;
240         char *cg_dir = (char *)data;
241         struct memory_limit_event *mle;
242         _cleanup_free_ struct cgroup_memory_stat *mem_stat = NULL;
243
244         mle = g_hash_table_lookup(memory_limit_hash, cg_dir);
245         if (!mle) {
246                 _E("invalid event\n");
247                 return false;
248         }
249
250         result = read(fd, &dummy_efd, sizeof(dummy_efd));
251         if (result < 0) {
252                 _E("[DEBUG] wrong eventfd %s\n", cg_dir);
253                 goto remove_mle;
254         }
255
256         if (access(cg_dir, F_OK) == -1) {
257                 _D("[DEBUG] there is no (%s) cgroup any longer, removing it", cg_dir);
258                 goto remove_mle;
259         }
260
261         result = cgroup_read_node_uint32(cg_dir, MEMCG_SWAP_USAGE, &usage);
262         if (result < 0) {
263                 result = cgroup_read_node_uint32(cg_dir, MEMCG_USAGE, &usage);
264                 if (result < 0) {
265                         _D("[DEBUG] there is no (%s) cgroup any longer, removed it", cg_dir);
266                         goto remove_mle;
267                 }
268         }
269
270         if (usage < mle->threshold) {
271                 _D("[DEBUG] (%s) cgroup escaped low memory status. usage(%d), threshold(%d)",
272                         cg_dir, usage, mle->threshold);
273                 return true;
274         }
275
276         result = memcg_get_memory_stat(cg_dir, &mem_stat);
277         if (result < 0) {
278                 _E("[DEBUG] Failed to get memory status : %s", cg_dir);
279                 goto remove_mle;
280         }
281
282         switch (mle->action) {
283                 case PROC_ACTION_BROADCAST:
284                         main_pid = get_main_pid(cg_dir, &max_mem);
285                         if (main_pid <= 0) {
286                                 _D("[DEBUG] there is no victim, removed cgroup : %s", cg_dir);
287                                 goto remove_mle;
288                         }
289
290                         if (lowmem_limit_broadcast(main_pid)) {
291                                 _E("[DEBUG] Failed to broadcast of process (%s)", cg_dir);
292                                 return false;
293                         }
294                         break;
295                 case PROC_ACTION_RECLAIM:
296                         lowmem_trigger_swap(0, cg_dir, false);
297                         break;
298                 case PROC_ACTION_KILL:
299                         main_pid = get_main_pid(cg_dir, &max_mem);
300                         if (main_pid <= 0) {
301                                 _D("[DEBUG] there is no victim, removed cgroup : %s", cg_dir);
302                                 goto remove_mle;
303                         }
304                         safe_kill(main_pid, SIGTERM);
305
306                         if (mle->pid == -1) {
307                                 mle->pid = main_pid;
308                                 g_timeout_add_seconds(2, liveness_check_cb, mle);
309                         }
310
311                         break;
312                 default:
313                         _E("[DEBUG] Unkown action of memory threshold");
314         }
315
316         return true;
317
318 remove_mle:
319         g_hash_table_remove(memory_limit_hash, cg_dir);
320         return false;
321 }
322
323 int lowmem_reassign_limit(const char *dir,
324                 unsigned int limit, enum proc_action action)
325 {
326         int fd;
327         fd_handler_h fdh = NULL;
328         gpointer hash_entry;
329         struct memory_limit_event *mle = NULL;
330         char buf[MAX_DEC_SIZE(int)] = {0};
331
332         if (memory_limit_hash) {
333                 /* TO DO: currently concurrent processes with same app name are located
334                  * in the same directory.
335                  * Fix to distinguish processes with the same app name
336                  */
337                 hash_entry = g_hash_table_lookup(memory_limit_hash, dir);
338                 if (hash_entry) {
339                         mle = (struct memory_limit_event *)hash_entry;
340                         if (mle->threshold == limit) {
341                                 return RESOURCED_ERROR_NONE;
342                         }
343                 }
344         }
345         else {
346                 memory_limit_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
347                                 NULL, memory_limit_hash_destroy);
348                 if (!memory_limit_hash) {
349                         _E("[DEBUG] Failed to create hash table");
350                         return RESOURCED_ERROR_FAIL;
351                 }
352         }
353
354         check_oom_and_set_limit(dir, limit * 1.2);
355         snprintf(buf, sizeof(buf), "%d", limit);
356
357         if (mle) {
358                 mle->threshold = limit;
359                 memcg_init_eventfd(mle->fd, dir, registerpath, buf);
360                 return RESOURCED_ERROR_NONE;
361         }
362
363         fd = memcg_set_eventfd(dir, registerpath, buf);
364         if (fd > 0) {
365                 mle = calloc(1, sizeof(struct memory_limit_event));
366                 if (!mle) {
367                         _E("[DEBUG] out of memory");
368                         return RESOURCED_ERROR_OUT_OF_MEMORY;
369                 }
370                 mle->fd = fd;
371                 mle->path = (char *)strdup(dir);
372                 if (!mle->path) {
373                         _E("[DEBUG] out of memory");
374                         free(mle);
375                         return RESOURCED_ERROR_OUT_OF_MEMORY;
376                 }
377                 mle->action = action;
378                 mle->threshold = limit;
379                 mle->pid = -1;
380                 add_fd_read_handler(fd, memory_action_cb, mle->path, NULL, &fdh);
381                 mle->fdh = fdh;
382                 g_hash_table_insert(memory_limit_hash, (gpointer)mle->path,
383                                 (gpointer)mle);
384
385                 return RESOURCED_ERROR_NONE;
386         }
387
388         return fd;
389 }
390
391 int lowmem_limit_move_cgroup(struct proc_app_info *pai)
392 {
393         GSList *iter = NULL;
394         _cleanup_free_ char *path = NULL;
395         int ret;
396
397         if (!pai)
398                 return RESOURCED_ERROR_NO_DATA;
399
400         if (!pai->memory.use_mem_limit)
401                 return RESOURCED_ERROR_NO_DATA;
402
403         ret = asprintf(&path, "%s/%s", MEMCG_HIGH_PP_PATH, pai->appid);
404         if (ret < 0) {
405                 _E("not enough memory");
406                 return RESOURCED_ERROR_OUT_OF_MEMORY;
407         }
408         cgroup_write_pid_fullpath(path, pai->main_pid);
409         if (pai->childs) {
410                 gslist_for_each_item(iter, pai->childs)
411                         cgroup_write_pid_fullpath(path, GPOINTER_TO_PID(iter->data));
412         }
413         return RESOURCED_ERROR_NONE;
414 }
415
416 void lowmem_limit_set_system_service(pid_t pid, unsigned int limit,
417                 const char *name, enum proc_action action)
418 {
419         _cleanup_free_ char *path = NULL;
420         int result;
421         unsigned int totalram = lowmem_get_totalram();
422
423         if (limit < MIN_LIMIT_VALUE || limit > totalram) {
424                 _E("[DEBUG] It's meaningless to set memory limit with size (%d)", limit);
425                 return;
426         }
427
428         if (!name) {
429                 _E("[DEBUG] service name is NULL");
430                 return;
431         }
432
433         result = asprintf(&path, "%s/%s", MEMCG_HIGH_PP_PATH, name);
434         if (result < 0) {
435                 _E("[DEBUG] not enough memory");
436                 return;
437         }
438
439         result = cgroup_make_subdir(MEMCG_HIGH_PP_PATH, name, NULL);
440         if (result < 0) {
441                 _E("[DEBUG] Failed to create cgroup subdir '%s/%s'",
442                                 MEMCG_HIGH_PP_PATH, name);
443                 return;
444         }
445
446         result = lowmem_reassign_limit(path, limit, action);
447         if (result < 0) {
448                 _W("Failed to reassign limit for %s", path);
449                 return;
450         }
451
452         result = cgroup_write_node_uint32(path, MEMCG_MOVE_CHARGE, 3U);
453         if (result < 0)
454                 _W("[DEBUG] Failed to set immigrate mode for %s (non-crucial, continuing)", path);
455
456         cgroup_write_pid_fullpath(path, pid);
457 }
458
459 int lowmem_limit_set_app(unsigned int limit, struct proc_app_info *pai,
460                 enum proc_action action)
461 {
462         _cleanup_free_ char *path = NULL;
463         GSList *iter = NULL;
464         int result;
465         unsigned int totalram = lowmem_get_totalram();
466
467         if (limit < MIN_LIMIT_VALUE || limit > totalram) {
468                 _E("[DEBUG] It's meaningless to set memory limit with size (%d)", limit);
469                 return RESOURCED_ERROR_INVALID_PARAMETER;
470         }
471
472         if (!pai) {
473                 _E("process app information is NULL");
474                 return RESOURCED_ERROR_INVALID_PARAMETER;
475         }
476
477         result = asprintf(&path, "%s/%s", MEMCG_HIGH_PP_PATH, pai->appid);
478         if (result < 0) {
479                 _E("not enough memory");
480                 return RESOURCED_ERROR_OUT_OF_MEMORY;
481         }
482
483         result = cgroup_make_subdir(MEMCG_HIGH_PP_PATH, pai->appid, NULL);
484         if (result < 0) {
485                 _E("Failed to create cgroup subdir '%s/%s'",
486                                 MEMCG_HIGH_PP_PATH, pai->appid);
487                 return result;
488         }
489
490         result = lowmem_reassign_limit(path, limit, action);
491         if (result < 0) {
492                 _W("Failed to reassign limit for %s", path);
493                 return result;
494         }
495
496         result = cgroup_write_node_uint32(path, MEMCG_MOVE_CHARGE, 3U);
497         if (result < 0)
498                 _W("Failed to set immigrate mode for %s (non-crucial, continuing)", path);
499
500         cgroup_write_pid_fullpath(path, pai->main_pid);
501         if (pai->childs) {
502                 gslist_for_each_item(iter, pai->childs)
503                         cgroup_write_pid_fullpath(path, GPOINTER_TO_PID(iter->data));
504         }
505
506         pai->memory.use_mem_limit = true;
507
508         return RESOURCED_ERROR_NONE;
509 }
510
511 static int lowmem_limit_app(void *data)
512 {
513         int error;
514
515         assert(data);
516
517         struct proc_limit_status *pls = (struct proc_limit_status *)data;
518
519         error = lowmem_limit_set_app(pls->limit, pls->ps.pai, pls->action);
520         if (!error)
521                 pls->ps.pai->memory.memlimit_update_exclude = true;
522         return RESOURCED_ERROR_NONE;
523 }
524
525 static int lowmem_limit_system_service(void *data)
526 {
527         assert(data);
528
529         struct proc_limit_status *pls = (struct proc_limit_status *)data;
530
531         lowmem_limit_set_system_service(pls->ps.pid, pls->limit, pls->ps.pci->name, pls->action);
532         return RESOURCED_ERROR_NONE;
533 }
534
535 static int lowmem_limit_service(void *data)
536 {
537         assert(data);
538
539         struct proc_status *ps = (struct proc_status *)data;
540
541         if (ps->pai && ps->pai->memory.memlimit_update_exclude)
542                 return RESOURCED_ERROR_NONE;
543
544         if (mem_service_limit) {
545                 lowmem_limit_set_app(mem_service_limit, ps->pai, mem_service_action);
546         }
547         return RESOURCED_ERROR_NONE;
548 }
549
550 static int lowmem_limit_appwidget(void *data)
551 {
552         assert(data);
553
554         struct proc_status *ps = (struct proc_status *)data;
555
556         if (ps->pai && ps->pai->memory.memlimit_update_exclude)
557                 return RESOURCED_ERROR_NONE;
558
559         if (mem_guiapp_limit && ps->pai->type == PROC_TYPE_GUI) {
560                 lowmem_limit_set_app(mem_guiapp_limit, ps->pai, mem_guiapp_action);
561         }
562         if (mem_widget_limit && ps->pai->type == PROC_TYPE_WIDGET) {
563                 lowmem_limit_set_app(mem_widget_limit, ps->pai, mem_widget_action);
564         }
565
566         return RESOURCED_ERROR_NONE;
567 }
568
569 static int lowmem_limit_bgapp(void *data)
570 {
571         assert(data);
572
573         struct proc_status *ps = (struct proc_status *)data;
574
575         if (ps->pai && ps->pai->memory.memlimit_update_exclude)
576                 return RESOURCED_ERROR_NONE;
577
578         lowmem_limit_set_app(mem_bgapp_limit, ps->pai, mem_bgapp_action);
579
580         return RESOURCED_ERROR_NONE;
581 }
582
583 static int lowmem_limit_fgapp(void *data)
584 {
585         assert(data);
586
587         struct proc_status *ps = (struct proc_status *)data;
588
589         if ((mem_guiapp_limit && ps->pai->type == PROC_TYPE_GUI) ||
590             (mem_widget_limit && ps->pai->type == PROC_TYPE_WIDGET))
591                 return lowmem_limit_appwidget(data);
592
593         _E("[DEBUG] Unable to set foreground app limit - app type not supported");
594
595         return RESOURCED_ERROR_NONE;
596 }
597
598 void lowmem_memory_init(unsigned int service_limit, unsigned int widget_limit,
599                 unsigned int guiapp_limit, unsigned int bgapp_limit)
600 {
601         mem_service_limit = service_limit;
602         mem_widget_limit = widget_limit;
603         mem_guiapp_limit = guiapp_limit;
604         mem_bgapp_limit = bgapp_limit;
605 }
606
607 void lowmem_action_init(int service_action, int widget_action,
608                 int guiapp_action, int bgapp_action)
609 {
610         if (service_action > 0)
611                 mem_service_action = service_action;
612
613         if (widget_action > 0)
614                 mem_widget_action = widget_action;
615
616         if (guiapp_action > 0)
617                 mem_guiapp_action = guiapp_action;
618
619         if (bgapp_action > 0)
620                 mem_bgapp_action = bgapp_action;
621 }
622
623 void lowmem_limit_init(void)
624 {
625         int result;
626         unsigned int usage;
627
628         mem_limit = MEM_LIMIT_TRHESHOLD;
629         result = cgroup_read_node_uint32(MEMCG_PATH, MEMCG_SWAP_USAGE, &usage);
630         if (result == RESOURCED_ERROR_NONE)
631                 registerpath = MEMCG_SWAP_USAGE;
632         else
633                 registerpath = MEMCG_USAGE;
634
635         register_notifier(RESOURCED_NOTIFIER_LIMIT_SYSTEM_SERVICE, lowmem_limit_system_service);
636         register_notifier(RESOURCED_NOTIFIER_LIMIT_APP, lowmem_limit_app);
637         if (mem_limit == MEM_LIMIT_NONE)
638                 return;
639
640         if (mem_service_limit)
641                 register_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, lowmem_limit_service);
642         if (mem_guiapp_limit || mem_widget_limit)
643                 register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_limit_appwidget);
644         if (mem_bgapp_limit) {
645                 if (!mem_guiapp_limit || !mem_widget_limit) {
646                         _W("Background app limit requires that both GUIApp and Widget limits to be set to work properly. Ignoring.");
647                 } else {
648                         register_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, lowmem_limit_bgapp);
649                         register_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, lowmem_limit_fgapp);
650                         register_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, lowmem_limit_fgapp);
651                         register_notifier(RESOURCED_NOTIFIER_WIDGET_BACKGRD, lowmem_limit_bgapp);
652                 }
653         }
654 }
655
656 void lowmem_limit_exit(void)
657 {
658         if (memory_limit_hash) {
659                 g_hash_table_destroy(memory_limit_hash);
660 #ifdef _UNIT_TEST
661                 memory_limit_hash = NULL;
662 #endif
663         }
664
665         unregister_notifier(RESOURCED_NOTIFIER_LIMIT_SYSTEM_SERVICE, lowmem_limit_system_service);
666         unregister_notifier(RESOURCED_NOTIFIER_LIMIT_APP, lowmem_limit_app);
667         unregister_notifier(RESOURCED_NOTIFIER_SERVICE_LAUNCH, lowmem_limit_service);
668         unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_limit_appwidget);
669         unregister_notifier(RESOURCED_NOTIFIER_APP_BACKGRD, lowmem_limit_bgapp);
670         unregister_notifier(RESOURCED_NOTIFIER_APP_FOREGRD, lowmem_limit_fgapp);
671         unregister_notifier(RESOURCED_NOTIFIER_WIDGET_FOREGRD, lowmem_limit_fgapp);
672         unregister_notifier(RESOURCED_NOTIFIER_WIDGET_BACKGRD, lowmem_limit_bgapp);
673 }