android 进程保活6.0_android-article

#进程保活机制

进程保活:说白了就是尽量的保证你的App不被系统杀死,或者被杀死后,还能后“复活”。以下介绍进程保活的几种常用方式。

Android杀死进程的机制来自于linux的low memory killer,他会对所有的进程进行一个排名,衡量的参数就是oom_adj。此值越大,进程越容易被系统杀死。 一般系统应用oom_adj的值都是小于0的,比如系统的启动init进程,oom_ajd = -16

**查看oom_adj值:**oom_adj:这个值越大,标明此进程越容易被回收。系统进程这个值都是小于0的。

adb shell cat /proc/pid(你的进程id)/oom_adj

pid的获取命令:ps | grep 进程名

首先我们看一下系统杀死app的优先级(从高到低,越低越容易被杀掉):

前台进程: 你当前正在使用的app进程,这是最后被系统杀死的进程。查看oom_adj,值为0

可见进程: 可见进程不包含任何的前台组件,可见进程依然会影响用户在屏幕上可以看到的内容。比如:activity弹出来一个不全屏的Dialog。从代码角度来说:就是调用了onPause,但是没有调用onStop。 查看oom_adj,值为1

服务进程: app进程启动了一个Servie,并且该进程并没有和任何的界面做绑定。 oom_adj 值为

后台进程: app退出后,会持有一个Activity,从代码逻辑上来说,就是activity没有调用onDestroy。 oom_adj值为7

空进程: app退出后,不包含任何活动的组件,从代码角度来说就是activity调用了onDestroy,但是系统还没有进行回收。该进程是最先被系统kill的。 oom_adj值为9

以上不同进程的oom_adj根据不同的具体手机,可能会有不同,仅仅是反应了一个趋势。

在Android系统里,进程被杀的原因通常为以下几个方面:

a. 应用Crash

b. 系统回收内存

c. 用户触发

d. 第三方root权限app.

本文仅仅是讨论前两种,通过以下发发实现后,你也会发现oom_adj的值确实变小了,这就意味着从low memeo killer 的角度来说,已经完成。一般来说:你通过用户触发的方式,你会得到onDestory的响应,这样你是可以做一些操作处理的。但是通过X60这种方式,你会发现:你根本不会相应onDestroy。而且它会把你杀的干干净净。由此我们也可以加单的猜测:X60这种清理方式:不仅仅是清理你的原始app的进程,他也会把你启动的另一个进程kill掉(可以根据包名查到你启动的相关的进程)从而无法相互唤醒(猜测而已)。

1。 前台服务(带有Notification)

设置前台服务,通过这样的方式,就会出现一个Notification来告知用户,比如QQ音乐。这种实现的方式比较简单:实现Service的时候,通过接口:setForeground(int id, Notification notification)就可以实现前台服务。这个属于上述中的“前台进程”;

缺点:会出现一个Notification,这个用户是的感知的,一般用户不喜欢这个东西的存在。

2。 通过Android的系统漏洞实现前台服务(无Notification)

利用系统的漏洞来启动一个前台Service进程。与普通启动方式的区别在于:没有生成一个Notification,用户感知不到(这是一个漏洞,android后续版本可能会随时的关闭)。

API<18:启动前台Service时直接传入一个new Notification()即可。

API>18:同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理(这是个android漏洞,我自己测试了galaxy s6 android 6.0是可以的)

**查看是否启动成功:**adb shell dumpsys activity services packagename。回车,查看isForground字段是否为true。

具体的代码如下所示:

@Override public int onStartCommand(Intent intent, int flags, int startId) {

if (Build.VERSION.SDK_INT < 18) {

startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标

}

else {

Intent innerIntent = new Intent(this, SecondService.class);

startService(innerIntent);

startForeground(GRAY_SERVICE_ID, new Notification());

}

}

public static class SecondService extends Service {

@Override public void onCreate() {

super.onCreate();

}

@Override public int onStartCommand(Intent intent, int flags, int startId) {

startForeground(GRAY_SERVICE_ID, new Notification());

stopSelf();

return super.onStartCommand(intent, flags, startId);

}

@Override public IBinder onBind(Intent intent) {

return null;

}

}

通过上面的代码后,你在查看你进程的oom_adj。你会发现发生了很大的变化。

3。 通过多进程相互唤醒机制

**多进程启动:**在老的进程中新启动一个前台进程ServcieNew(通过上述的方案2),SericeNew进程每个一段时间检查换上一个进程是否存在,如果不存在立马启动,或者通过广播的方式发送广播,通知老的进程重新启动业务逻辑。

多进程需要注意的地方:你的老的进程的Application的onCreate会被调用两次,这个地方一般都是用来初始化操作,多进程需要通过AIDL或者广播的方式进程通信。

Application的onCreate会被调用两次的解决方法:

@Override public void onCreate() {

super.onCreate();

Log.d(TAG, "onCreate function");

int pid = Process.myPid();

String processName = null;

ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);

for (ActivityManager.RunningAppProcessInfo appProcess : actManager.getRunningAppProcesses()) {

if (appProcess.pid == pid) {

processName = appProcess.processName;

}

}

if (processName.equals(getPackageName())) {

init();

}

}

以下通过广播的方式来说明,具体的实现方式如下:

首先在你的老的进程中实现一个静态广播(在Androidmaniest.xml中声明该广播,这样程序就算被杀掉了也可以收到该广播)BroadcastReceiver :

public class RecoveryReceiver extends BroadcastReceiver {

private final static String TAG = WakeReceiver.class.getSimpleName();

private final static int RECOVERY_SERVICE_ID = -110;

public final static String RECOVERY_ACTION = "com.recovery.receiver";

@Override public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (RECOVERY_ACTION.equals(action)) {

Intent wakeIntent = new Intent(context, WakeNotifyService.class);

//收到此消息后启动自己的业务逻辑

}

}

}

其次在新启动的进程中,每隔一段时间发送一次广播(没有检测老的进行是否还存在),通知老进程启动业务逻辑,需要注意的是:新启动的进程也要使用进程保活机制,尽量的保证不能轻易的被系统杀掉:

private final static int ALARM_INTERVAL = 5 * 60 * 1000; //每个5分钟发送一次广播

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent alarmIntent = new Intent();

alarmIntent.setAction(RecoveryReceiver.RECOVERY_ACTION);

PendingIntent operation = PendingIntent.getBroadcast(this, WAKE_REQUEST_CODE, alarmIntent,

PendingIntent.FLAG_UPDATE_CURRENT);

alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), ALARM_INTERVAL,

operation);

**验证方式:**adb shell之后,kill掉你的第一个进程,然后等待看两一个Service能不能将该进程启动。

4。 通过系统广播来启动进程

Android提供了很多的系统广播,如:

系统重新启动

调用系统相拍照的广播(android4.0新增加了android.hardware.action.NEW_PICTURE、android.hardware.action.NEW_VIDEO,针对照片类型的APP,应用场景很大)等。

以拍照为例:

注册一个静态广播(静态广播在你程序不启动的时候就可以接收到,注意广播的exprote务必设置为true,否则你会接收不到,另外,这个不需要Camera等权限)

android:name=".PicReceiver"

android:enabled="true"

android:exported="true">

**验证方式:**adb shell之后,kill掉你的进程,然后拍照片看是否可以启动。

5。 通过SynAdapter

一种提高Android应用进程存活率新方法 来自csdn 作者:zgzhaobo

上述这种方法“利用Android系统提供的账号和同步机制实现”,进行被kill掉后,进程被系统kill后,可以由syn拉起。 缺点:用户可以单独的停止或者删除,而且有些手机是默认不同步,需要用户参与。个人感觉这种方案通用性不是很大。

关于Android系统账号可以参考文章:

Write your own Android Sync Adapter

Write your own Android Authenticator

6。 通过第三方的推送SDK

目前业界很多的第三方推送SDK(友盟、极光推送等),都是通过长链接的方式完成推送,我们就可以通过这些sdk来实现进程的保活。

总结: 以上介绍了low memoey killer 下的进程保活。其实,不管你采用哪种方式,当你的进程内存太大了,系统都会将你进程杀掉。以上手段只是辅助手段,降低进程的内存才是最终的手段。

7。应用Crash后的重新启动

在你的应用Crash之后,你是可以通过Android给你提供的消息回调进行相应的处理的,比如:保存crash日志等各种业务逻辑。目前很多手机Rom在你crash之后,会立马回到你刚才crash的页面,但是由于你代码的逻辑问题,你会发现该页面根本没有进行业务操作。有的时候,你当前的页面没有办法进行任何的操作来串起你的流程来。

这个时候建议crash之后,让你的app重启。不要让默认的Rom操作回到你原来crash的页面(当然有的Rom在你crash之后会重启应用,为了统一处理,这个逻辑最好还是我们自己来进行处理。这个逻辑最好放在你程序的基类当中,这样不管是那个一页面发生了crash,重新启动你都会进入到自己的重启流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值