【android 】进程、守护进程的实现及进程拉活

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/SunshineTan/article/details/53572073

1,概念

1)守护进程(Daemon)

是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某些任务。android中守护进程的实现主要由Service来完成。Android继承了Linux的lowmemorykiller,为了实现进程常驻,需要应用到守护进程。

2)进程拉活

android进程拉活包括2个层面:

①提高进程优先级,降低进程被杀死的概率。

②进程被杀死后,进行拉活。(守护进程主要做的事)

3)android内存管理机制:

当内存不足时,为了新建进程或运行更重要的进程,根据进程优先级,清除旧进程来回收系统资源。

2,实现思想

1)提升进程优先级

可通过提升进程优先级来保活进程。相关方案:查看3-(1)。进程重要性逐渐降低为:

①前台进程(Foreground process)

用户当前操作所必需的进程。内存不足以支持前台进程运行时,系统才终止该进程。

a.拥有用户正在交互的 Activity(已调用 onResume())

b.拥有绑定到用户正在交互的Activity的Service

c.拥有正在“前台”运行的 Service(服务已调用startForeground())

d.拥有正执行一个生命周期回调的 Service(onCreate()、onStart() 或 onDestroy())

e.拥有正执行其onReceive() 方法的 BroadcastReceiver

②可见进程(Visible process)

没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。只有前台进程运行内存不足才终止。

a.拥有不在前台、但仍对用户可见的 Activity(已调用 onPause(),比如输入法进程)。

b.拥有绑定到可见(或前台)Activity的 Service

 ③服务进程(Service process)

通常执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。只有前台进程、可见进程内存不足才终止。

a. 正在运行startService() 方法启动的服务,且不属于上述两个更高类别进程的进程。

④后台进程(Background process)

后台进程对用户体验没有直接影响,系统可能随时终止它们。

a.对用户不可见的Activity 的进程(已调用 Activity的onStop() 方法)

⑤空进程(Empty process)

保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。

a.不含任何活动应用组件的进程

3.实现demo

1)提升进程优先级:

利用activity提升权限(放一个像素在前台

a.实现:

监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将Activity 销毁掉。注意该 Activity 需设计成用户无感知。QQ黑科技之一。
通过该方案,可以使进程的优先级在屏幕锁屏时间由4提升为最高优先级1。

b.场景:

本方案主要解决第三方应用及系统管理工具在检测到锁屏事件后一段时间(一般为5分钟以内)内会杀死后台进程,已达到省电的目的问题。     

添加Manifest文件属性值为android:persistent=“true”

大神说,如果用系统shareuid+系统签名,就可以保证即使前台activity黑屏,该进程都死不掉。。。。反正我没机会试( TNT)

2)进程拉活

①利用广播拉活

注册广播监听器,在发生响应事件时拉活。

i>常用系统广播:

       a.开机广播

         详情查看:http://blog.csdn.net/sunshinetan/article/details/53126857

       b.网络变化广播

       c.文件挂载广播

       d.屏幕亮灭广播

       e.锁屏解锁广播

       f.应用安装卸载广播

缺点:

        a.广播接收器被管理软件、系统软件通过“自启管理”等功能禁用的场景无法接收到广播,从而无法自启。

 

        b.系统广播事件不可控,只能保证发生事件时拉活进程,但无法保证进程挂掉后立即拉活。

ii>第三方应用广播

通过反编译第三方 Top 应用,如:手机QQ、微信、支付宝、UC浏览器等,以及友盟、信鸽、个推等 SDK,找出它们外发的广播,在应用中进行监听,这样当这些应用发出广播时,进行应用拉活。

缺点:

        第三方应用的广播属于应用私有,当前版本中有效的广播,在后续版本随时就可能被移除或被改为不外发。

②利用Service拉活(如何保证Service的存活)

i>START_STICKY状态

       代码如下,将Service 设置为 START_STICKY,利用系统机制在 Service 挂掉后自动拉活。kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样。

 注意:

        a.Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。

        b.进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。

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

    	return Service.START_STICKY;
    }

ii>提升Service优先级、Service进程优先级:将Service设置为前台服务

       将后台Service设置为前台Service,将进程优先级由4提升为2。前台Service是用户可感知的,对于不需要常驻通知栏的应用,采用Notification来实现:

       实现一个内部 Service,在 LiveService 和其内部 Service 中同时发送具有相同 ID 的 Notification,然后将内部 Service 结束掉。随着内部 Service 的结束,Notification 将会消失,但系统优先级依然保持为2。  

        可以使用startForeground()将service放到前台状态。

        如果在极度极度低内存的压力下,该service还是会被kill掉,并且不一定会restart()

        另外也可以放一个像素在前台(手机QQ)来实现。

iii>服务互相绑定

        跨进程bind一个service之后,如果被bind的service挂掉,bind他的service会把他拉起来。

iv>onDestroy方法里重启service

      service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service,或者直接在onDestroy()里startService。

       当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证。

v>在JNI层,用C代码fork一个进程出来

        这样产生的进程,会被系统认为是两个不同的进程.但是Android5.0之后可能不行.

vi>root之后放到system/app变成系统级应用

③利用Native进程拉活(守护线程)

i>实现:

       利用Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native 进程中立即对主进程进行拉活。

a.在Native进程中感知主线程存活,当主进程不存活时进行拉活。

方法一:

         在Native进程中,通过死循环或定时器,轮训判断主进程是否存活。缺点:不停的轮询执行判断逻辑,非常耗电。

方法二(推荐):

         在主进程中创建一个监控文件,在主进程中持有文件锁。拉活进程启动后,申请文件锁将会被堵塞,一旦可以成功获取到锁,说明主进程挂掉,即可进行拉活。

         原理:不论windows还是linux都会有一套文件的进程同步机制,为了各个进程间文件的同步问题,一个进程可以给一个文件上锁,操作完了之后再解锁,其他进程如果担心同步问题,会首先检查一下文件是否有锁,如果有锁,代表别人正在操作,就会延迟对文件的操作。那么当一个进程挂掉,他给文件加的锁也自然会消失。

          为了实现双向守护进程,进程a给文件1加锁,阻塞读取文件2的锁。进程b给文件2加锁,阻塞读取文件1的锁。如果对方进程挂掉,即可读取到对方所持有文件锁的文件,即可监听到对方挂掉。

b.在Native进程中拉活主进程。

       方法一:通过am命令进行拉活。通过指定“—include-stopped-packages”参数来拉活主进程处于 forestop 状态的情况。

c.保证Native进程唯一性。

      方法一:将 Native 进程设计成 C/S 结构模式,主进程与 Native 进程通过 Localsocket 进行通信。在Native进程中利用 Localsocket 保证 Native 进程的唯一性,不至于出现创建多个 Native 进程以及 Native 进程变成僵尸进程等问题。

ii>主要原理:

      在 Android 中所有进程和系统组件的生命周期受 ActivityManagerService 的统一管理。而且,通过 Linux 的 fork 机制创建的进程为纯 Linux 进程,其生命周期不受 Android 的管理。

iii>适用范围:

      适用于android5.0以下版本。

      对于 Android5.0 以上手机,系统虽然会将native进程内的所有进程都杀死,这里其实就是系统“依次”杀死进程时间与拉活逻辑执行时间赛跑的问题,如果可以跑的比系统逻辑快,依然可以有效拉起,故在某些 Android 5.0 以上机型有效。 

      适用Android以上机型demo(征服android 5.1无问题):http://download.csdn.net/detail/sunshinetan/9709469

④利用账户同步机制拉活

     android系统有一个账户系统,设置一个自己的账户,android会定期唤醒账户更新服务。我们可以自己设定同步的事件间隔,且发起更新的是系统,不会受到任何限制。需要在 AndroidManifest 中定义账号授权与同步服务。

     Android 版本(Android N)中系统对账户同步这里做了变动,该方法不再有效。

缺点:

       a.用户会在系统设置的账户列表里面看到一个不认识的账户;

       b.同步的事件间隔是有限制的,最短1分钟,见源码,如果小雨60秒,置为60秒;

       c.用户可以卸载账户;

       d.必须联网!google提供这个组件是让你同步账户信息,不联网就不能保活!

4,用途

 守护进程,与进程常驻、进程拉活做的是同一类事情。

 1)锁屏应用正常为用户服务。

 2)IM类应用,需要在后台维护一个长链接,以便于及时将信息传递给yoghurt。

 3)一些专用设备,在工作的时候需要实现软件常驻界面。

5,如何判断应用被强杀

在Application中定义一个static常量,赋值为-1,在欢迎界面改为0,如果被强杀,application重新初始化,在父类Activity判断该常量的值。

 

 

 

展开阅读全文

没有更多推荐了,返回首页