关于防止App被第三方应用Kill掉的问题
由于一些需求的原因需要让自己App长时间在后台。虽然这样的做法是很Orz的,但是由于项目需求有时候不得不这样做。QQ、微信之所以没被第三方应用直接给kill掉,从市场原因腾讯的软件已经深入人心,很多厂家或是软件早就把这些软件加入白名单中!
但是作为App的开发人员来说肯定是强烈建议不要这么做,不仅仅从用户角度考虑,作为Android开发者也有责任去维护Android的生态环境。就是因为越来越多的这样的占用系统内存的进程越来越多才使得android手机越来越卡,android碎片化的原因越来越多的第三方App可以通过清理内存的方式将后台进程给直接Kill掉来增加run可用内存。
但是通过技术层面如何解决这个不被kill掉进程的问题呢?
- Service设置成START_STICKY,kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样。(PM1中提供参考)
- 通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别,除非在系统内存非常缺,否则此进程不会被 kill
- 双进程Service:让2个进程互相保护,其中一个Service被清理后,另外没被清理的进程可以立即重启进程
- QQ黑科技:在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死
- 在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用(Android4.0系列的一个漏洞,已经确认可行)
- Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android-Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以下可行)
- 用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。
- 在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。
- 主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。
- 联系厂商,加入白名单
PM1:
for (RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE)) {
if("com.XXX.XXX.XXXService".equals(service.service.getClassName())){
isServiceRunning = true;
}
}
if (!isServiceRunning ) {
Intent i = new Intent(context, com.XXX.XXX.XXXService.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(i);
}
Notification notification =
new
Notification(R.drawable.icon,
"服务开启"
, System.currentTimeMillis());
notification.flags|= Notification.FLAG_NO_CLEAR;
notification.flags=Notification.FLAG_ONGOING_EVENT;
Intent notificationIntent =
new
Intent(
this
, MainActivity.
class
);
PendingIntent pendingIntent = PendingIntent.getActivity(
this
,
0
, notificationIntent,
0
);
notification.setLatestEventInfo(
this
,
"service"
,
"防止服务被任务管理器所杀"
, pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);
后来一次 做自定义Notification的时候,通知栏没有显示通知,查看后发现 service 也没被kill 。所以就进一步去研究了下 最后发现 只用两行代码就能保持服务不会被kill,并且不会有通知栏通知代码如下:
1
2
|
Notification notification = new Notification(); startForeground( 1 , notification); |
实例代码如下:
public
class
TestService
extends
Service {
private
static
final
Class[] mStartForegroundSignature =
new
Class[] {
int
.
class
, Notification.
class
};
private
static
final
Class[] mStopForegroundSignature =
new
Class[] {
boolean
.
class
};
private
NotificationManager mNM;
private
Method mStartForeground;
private
Method mStopForeground;
private
Object[] mStartForegroundArgs =
new
Object[
2
];
private
Object[] mStopForegroundArgs =
new
Object[
1
];
@Override
public
IBinder onBind(Intent intent) {
return
null
;
}
@Override
public
void
onCreate() {
super
.onCreate();
mNM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
try
{
mStartForeground = TestService.
class
.getMethod(
"startForeground"
,
mStartForegroundSignature);
mStopForeground = TestService.
class
.getMethod(
"stopForeground"
,
mStopForegroundSignature);
}
catch
(NoSuchMethodException e) {
mStartForeground = mStopForeground =
null
;
}
// 我们并不需要为 notification.flags 设置 FLAG_ONGOING_EVENT,因为
// 前台服务的 notification.flags 总是默认包含了那个标志位
Notification notification =
new
Notification();
// 注意使用 startForeground ,id 为 0 将不会显示 notification
startForegroundCompat(
1
, notification);
}
@Override
public
void
onDestroy() {
super
.onDestroy();
stopForegroundCompat(
1
);
}
// 以兼容性方式开始前台服务
private
void
startForegroundCompat(
int
id, Notification n) {
if
(mStartForeground !=
null
) {
mStartForegroundArgs[
0
] = id;
mStartForegroundArgs[
1
] = n;
try
{
mStartForeground.invoke(
this
, mStartForegroundArgs);
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
return
;
}
mNM.notify(id, n);
}
// 以兼容性方式停止前台服务
private
void
stopForegroundCompat(
int
id) {
if
(mStopForeground !=
null
) {
mStopForegroundArgs[
0
] = Boolean.TRUE;
try
{
mStopForeground.invoke(
this
, mStopForegroundArgs);
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
return
;
}
// 在 setForeground 之前调用 cancel,因为我们有可能在取消前台服务之后
// 的那一瞬间被kill掉。这个时候 notification 便永远不会从通知一栏移除
mNM.cancel(id);
}
}
通过查询资料有人提到这个program:: droidwolf/NativeSubprocess · GitHub
创建 linux 子进程的 so 库,当初用在 service 免杀上,经测试,在大部分机子上有用。NativeSubprocess 是一个可以让你在 android 程序中创建 linux 子进程并执行你的 java 代码的 so 库。由于市面上典型的内存清理工具值清理 apk 包关联的进程,而不会处理 linux 原生进程。回头试试看这样是否好使。
参考文章:http://www.jb51.net/article/73976.htm
最后的最后还是要说:请不要做流氓软件!!让本来就碎片化的Android手机能运行的更顺畅。
关于防止App被第三方应用Kill掉的问题的更多相关文章
- Android: HowTo设置app不被系统kill掉
有一种方法可以设置app永远不会被kill,AndroidManifest.xml 中添加: android:persistent="true" 适用于放在/system/app下 ...
- Android 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护
本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context ↳an ...
- Android下写一个永远不会被KILL掉的进程/服务
Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用.当系统觉得当前的资源非常有限的时候,为了保证一些优先级高的程序能运行,就会杀掉一些 ...
- 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护
本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context ↳an ...
- 【代码】Android: 怎样设置app不被系统k掉
有一种方法可以设置app永远不会被kill,AndroidManifest.xml 中添加: android:persistent="true" 适用于放在/system/app下 ...
- mapreduce作业reduce被大量kill掉
之前有一段时间.我们的hadoop2.4集群压力非常大.导致提交的job出现大量的reduce被kill掉.同样的job执行时间比在hadoop0.20.203上面长了非常多.这个问题事实上是redu ...
- 防止Android程序被系统kill掉的处理方法
转载请注明出处:http://blog.csdn.net/cuiran/article/details/38851401 目前遇到一个问题程序需要一直运行,并显示在最前端,但是运行一段时间发现会被系统 ...
- ORACLE快速彻底Kill掉的会话
在ORACLE数据库当中,有时候会使用ALTER SYSTEM KILL SESSION 'sid,serial#'杀掉一个会话进程,但是使用这个SQL语句杀掉会话后,数据库并不会立即释放掉相关的资源 ...
- windows系统下在dos命令行kill掉被占用的pid (转)
原文出自:http://www.2cto.com/os/201304/203771.html windows系统下在dos命令行kill掉被占用的pid 1.开始-->运行-->c ...
随机推荐
- TCP/IP 和 Socket 的关系
要写网络程序就必须用Socket,这是程序员都知道的.而且,面试的时候,我们也会问对方会不会Socket编程?一般来说,很多人都会说,Socket编程基本就是listen,accept以及send,w ...
- JS表单验证-12个常用的JS表单验证
JS表单验证-12个常用的JS表单验证 最近有个项目用到了表单验证,小编在项目完结后的这段时间把常用的JS表单验证demo整理了一下,和大家一起分享~~~ 1. 长度限制 <p>1. 长度 ...
- java抽象-老师的生日-逻辑思维-有趣的面试题-遁地龙卷风
(-1)写在前面 都快去北京了,硬生生的安排一场java考试,对于那些特别细节的东西我忘了吧也不觉得有什么不好,以前都记得,也都见过,只不过平时不常用连接断了,但是你死记硬背是没用的,一段时间后还是会 ...
- centos 安装redis(一台机器可以安装多个redis)
我在运行时redis版本是2.8 操作前设置以管理员身份: 打开终端输入 su - 安装redis需要确保系统已经安装了(gcc gcc-c++)# yum -y install gcc gcc-c+ ...
- js中apply()和call()方法的使用
1.apply()方法 apply方法能劫持另外一个对象的方法,继承另外一个对象的属性. Function.apply(obj,args)方法能接收两个参数 obj:这个对象将代替Funct ...
- Proj.4库的编译及使用
Proj.4库的编译及使用 Proj.4是开源GIS最著名的地图投影库,GRASS GIS, MapServer, PostGIS, Thuban, OGDI, Mapnik, TopoCad, GD ...
- CUDA代码移植
如果CUDA的代码移植,一个是要 include文件夹对不对,这个是.h文件能否找到的关键,另一个就是lib,这个是.lib文件能否找到的关键.具体检查地方,见下头. include: lib:
- 封装一个mysql类(ggshop)
接口 abstract class db{ //连接服务器 public abstract function connect($n,$u,$p); //发送查询 protected abstract ...
- tp框架之数据添加
1.数组添加 //$attr = array("Code"=>"n088","Name"=>"哈萨克族"); ...
- 这两年在QQGame写过的游戏(2012.7.15-2014.8.25)
[雷电] Gamebryo http://qqgamecdnimg.qq.com/help/rule177.html [英雄杀] http://yxs.qq.com ...