Android应用防止被杀的方法

    Android 应用如果需要常驻后台运行且不能被杀,通常的办法是增加persist属性,并需要是系统预装的应用或者有系统签名。这样也不能完全保证lowmemkiller机制不会杀此应用,原因是 应用升级后(即此应用之前的版本persist属性是起作用的,新版本也是携带此属性的),应用的persist属性会自然失效,这是由android的机制决定的(下一篇文章解释)。此时新版本的应用就和普通的应用没有什么区别,随时会被Lowmemkill模块杀死,而不能达到常驻后台的需求。

这里提供一种可能的解决方案,我们先看lowmem的内存管理的机制,代码如下:

static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
	struct task_struct *tsk;
	struct task_struct *selected = NULL;
	unsigned long rem = 0;
	int tasksize;
	int i;
	short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
	int selected_tasksize = 0;
	short selected_oom_score_adj;
	int array_size = ARRAY_SIZE(lowmem_adj);
	int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
	int other_file = global_page_state(NR_FILE_PAGES) -
						global_page_state(NR_SHMEM) -
						total_swapcache_pages();

	if (lowmem_adj_size < array_size)
		array_size = lowmem_adj_size;
	if (lowmem_minfree_size < array_size)
		array_size = lowmem_minfree_size;
	for (i = 0; i < array_size; i++) {
		if (other_free < lowmem_minfree[i] &&
		    other_file < lowmem_minfree[i]) {
			min_score_adj = lowmem_adj[i];
			break;
		}
	}

	lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n",
			sc->nr_to_scan, sc->gfp_mask, other_free,
			other_file, min_score_adj);

	if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
		lowmem_print(5, "lowmem_scan %lu, %x, return 0\n",
			     sc->nr_to_scan, sc->gfp_mask);
		return 0;
	}

	selected_oom_score_adj = min_score_adj;

	rcu_read_lock();
	for_each_process(tsk) {
		struct task_struct *p;
		short oom_score_adj;

		if (tsk->flags & PF_KTHREAD)/*如果是内核线程,则直接跳过*/
			continue;

		p = find_lock_task_mm(tsk); /**如果是内存不相关的进程,也跳过**/
		if (!p)
			continue;

		if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
		    time_before_eq(jiffies, lowmem_deathpending_timeout)) {
			task_unlock(p);
			rcu_read_unlock();
			return 0;
		}
		oom_score_adj = p->signal->oom_score_adj;    /**获取oom_score_adj**/
		if (oom_score_adj < min_score_adj) {
			task_unlock(p);
			continue;
		}
		tasksize = get_mm_rss(p->mm);
		task_unlock(p);
		if (tasksize <= 0)
			continue;
		if (selected) {
			if (oom_score_adj < selected_oom_score_adj)
				continue;
			if (oom_score_adj == selected_oom_score_adj &&
			    tasksize <= selected_tasksize)
				continue;
		}
		selected = p;
		selected_tasksize = tasksize;
		selected_oom_score_adj = oom_score_adj;
		lowmem_print(2, "select %d (%s), adj %hd, size %d, to kill\n",
			     p->pid, p->comm, oom_score_adj, tasksize);
	}
	if (selected) {
		task_lock(selected);
		send_sig(SIGKILL, selected, 0);
		/*
		 * FIXME: lowmemorykiller shouldn't abuse global OOM killer
		 * infrastructure. There is no real reason why the selected
		 * task should have access to the memory reserves.
		 */
		if (selected->mm)
			mark_oom_victim(selected);
		task_unlock(selected);
		lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n",
			     selected->pid, selected->comm,
			     selected_oom_score_adj, selected_tasksize);
		lowmem_deathpending_timeout = jiffies + HZ;
		rem += selected_tasksize;
	}

	lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n",
		     sc->nr_to_scan, sc->gfp_mask, rem);
	rcu_read_unlock();
	return rem;
}
  从以上代码可以看出,Lowmemkiller的本质是遍历系统进程的oom_adj的值并结合占用内存的大小,选择合适的进程进行kill的。它首先排除了内核进程(即标记为PF_KTHREAD)的进程,然后按照oom_adj的大小进行选择,并结束进程的。这样就给我们提供了一种可能的方案,通过其他手段来直接修改
应用进程对应的oom_adj数值,使得Lowmemkiller模块按照既有的算法跳过我们的应用进程,即通过修改(需要特别通道支持):
							/proc/进程号/oom_adj
							/proc/进程号/oom_score_adj
的值为负数,通常为-11(系统针对persist属性应用设置的oom_adj的值),通常是在应用启动时和应用的lowmem回调方法中来设置,以防止应用被lowmemkiller杀死。此方法能满足绝大多数的情况,因为系统也会不定时的更新进程的oom_adj,所以此方案并不能完全避免被系统kill,但是基本能解决应用自升级到新版本后被Lowmemkiller杀死的可能.







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值