ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

im即时通讯开发之双进程守护保活实践

2022-06-27 14:36:20  阅读:233  来源: 互联网

标签:service 绑定 保活 之双 im 应用 进程 访问者


在Android 4.4及以后的系统中,应用能否常驻内存,一直以来都是相当头疼的事情,尤其移动端IM、消息推送这类应用,为了保证“全时在线”的概念,真是费尽了心思。

虽然APP常驻内存对于用户来说比较”恶心”,但是在诸如IM和消息推送这类场景来说,APP的常驻内存却尤其重要,而且很多时候用户也会要求APP能够保证长久运行。

因为Android机型太多太杂,以及各厂商定制ROOM的差异,Android应用保活没有一劳永逸和万能的方法。

 

 



常见的Android应用保活方法

1)监听广播方式:

通过监听一些全局的静态广播,比如开机广播、解锁屏广播、网络状态广播等,来启动应用的后台服务。目前,在高版本的Android系统中已经失效,因为高版本的Android系统规定应用必须在系统开机后运行一次才能监听这些系统广播,一般而言,应用被系统杀死后,基本无法接收系统广播。

2)提高Service的优先级:

以前提高Service优先级方法很多,比如onStartCommand返回START_STICKY使系统内存足够的时候Service能够自动启动、弹出通知、配置service的优先级等,这些方式只能在一定程度上缓解service被立马回收,但只要用户一键清理或者系统回收照样无效。

3)全局定时器:

还有一种方法就是在设置一种全局定时器,定时检测启动后台服务,但这种方法目前也已经无效,因为应用只要被系统杀死,全局定时器最后也只成了摆设。

4)应用中的双service拉起:

经过测试,只要当前应用被杀,任何后台service都无法运行,也无法自行启动。

5)应用中的双进程拉起:

这种方式就是传说中的使用NDK在底层fork出一个子进程,来实现与父进程之间的互拉。在Android4.x还是非常有效的,但是高版本的Android系统的系统回收策略已经改成进程组的形式了,如果系统要回收一个应用,必然会杀死同属于一个进程组的所有进程,因此最后导致双进程无法拉起。

剖析Android的Service

Service的特征类似于Activity,其区别是它没有交互界面,且可长时间运行在后台,即使它所属的应用已经退出,Service仍然可以继续在后台运行。Service无法自行启动,访问者启动它的方式分为两种,即startService(绑定式)和bindService (非绑定式),相关介绍如下。

startService:

即非绑定式。访问者使用这种方式启动service后,被启动的service将不受访问者控制,也无法与访问者进行数据通信,它会无限地运行下去,必须调用stopSelf()方法或者其他组件(包括访问者)调用stopService()方法来停止。它的生命周期:onCreate->onStartCommand()->……>onDestory(),其中,onCreate用于初始化工作,多次调用startService启动同一个服务,onCreate方法只会被调用一次,onStartCommand会被调用多次,onDestory在销毁时也只会被调用一次。即时通讯开发

 

 



bindService:

即绑定式。访问者使用这种方式启动service后,被启动的service受访问者的控制,访问者将通过一个IBinder接口的对象与被绑定的service进行通信,并且可以通过unbindService()方法随时关闭service。一个service可以同时被多个访问者绑定,只有当多个访问者都主动解除绑定关系之后,系统才会销毁service。它的生命周期:onCreate->onBind->....>onUnbind->onDestory,其中,onBind用于返回一个通信对象(IBinder)给访问者,访问者可以通过该IBinder对象调用service的相关方法。当多个访问者绑定同一个service时,onCreate只会被调用一次,onBind、unOnbind方法会被调用与访问者数目相关的次数,onDestory在销毁时只会被调用一次。

有一点需要注意的是:如果一个service被startService启动,然后其他组件再执行bindService绑定该service,service的onCreate不会再被回调,而是直接回调onBind方法;当该组件unBindService时,service的onUnbind方法被回调,但是service不会被销毁,直到自己调用stopSelf方法或者其他组件调用stopService方法时才会被销毁。

理解AIDL和远程Service调用

接上一节。bindService绑定方式启动service分为两种:本地service和远程service。

本地service是指绑定启动的service实现在它所属的应用进程中,其他组件访问者与本地service之间的通信是通过IBinder接口对象实现的;远程service是指绑定启动的service实现在其他应用进程中,也就是另一个APP中,他们之间的通信则是通过IBinder接口的代理对象实现的,而这个代理对象必须通过AIDL方式来构造。

AIDL(Android Interface DefinitionLanguage,即接口描述语言)使用用于约束两个进程之间通讯的规则,可以实现Android终端上两个不同应用(进程)之间的通信(IPC)。

AIDL实现的步骤非常简单,阐述如下:

1)在A应用创建IPerson.aidl接口文件(注意AIDL语言的编写规则,这里不详解);

2)将创建的IPerson.aidl接口文件拷贝到B应用中。

packagecom.person.aidl

interfaceIPerson{

       String getName();

       intgetAge();

然后:我们只需要保存.aidl文件,编译器就会自动生成所需的IPerson.java文件,保存在gen目录下,该文件包含一个内部类IPerson.Stub,它实际上继承于Binder对象,即充当通信所需的IBinder代理对象。

这里有几点需要注意,将会影响两进程之间是否能够通讯成功:

1)接口名与aidl文件名相同;

2)应用A、应用B中的.aidl文件必须相同,并且它们所属的包名也必须要一样。

先来看看单进程守护如何实现保活

我们先分析一下绑定方式启动Service流程。

以某Android应用(以下简称应用X)中的守护Service启动保活助手A的守护Service为例:

1)当应用X中的Service通过bindService绑定保活助手A的Service时,保活助手A会回调onBind方法返回一个IPerson.Stub的代理对象给应用X;

2)当应用XService中的onServiceConnected被回调时,说明应用X绑定保活助手A的Service成功;

3)当解绑时,应用X中的onServiceDisconnected和保活助手A中的onUnbind被调用。

有了前面的基础,接下来就分析如何在不同的应用进程中创建守护service,通过检测彼此的绑定情况来唤醒彼此:

1)当应用X绑定保活助手A时(浅绿色字体),如果保活助手A被系统杀死,应用X的onServiceDisConnected被回调,我们可以在该方法中执行bindService方法再次尝试绑定唤醒保活助手A;

2)当保活助手A绑定应用X时(橙色字体),如果应用X被系统杀死,保活助手A的onServiceDisconnected被回调,我们可以在该方法中执行bindService方法再次尝试绑定唤醒应用X。

至此,经过这种双重绑定守护来到达应用保活的目的。

新型双进程守护的保活实践

从程度上来说,单进程守护方式差不多可以满足应用长时间保活的要求,虽说让人感觉有点怪异,但实现起来也不是很难,效果明显。

但是,随着进一步的测试,我连续两次强杀应用X,应用X就无法启动了,这是因为当应用X“体积”较大,启动前需要加载诸如大量的静态变量或者Application类中的变量等,导致启动较慢,当我第一次强杀应用X时,保活助手A是执行绑定启动应用X保活服务的,但我继续第二次强杀应用X时,保活助手A可能还未与应用X绑定,最终导致保活助手A无法检查应用X的绑定状态而失效。

双进程守护:针对单进程守护出现的问题,当应用X“体积”较大时,我们可以采用双进程守护,即实现两个保活助手,它们彼此双向绑定来对应用X进行守护。我们采用“环”的形式来进行互拉,无论谁被杀死,只要系统杀掉剩余的任何一个进程,最后活着的进程都能够将其他被杀进程拉起来。当然,这里还有个小技巧,为了防止两个保活助手进程同时被系统杀死,我这里采取高低优先级的方式来解决。

标签:service,绑定,保活,之双,im,应用,进程,访问者
来源: https://www.cnblogs.com/weikeyun9/p/16415981.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有