本篇文章简单总结一下Android系统查杀进程的方式。
一、进程查杀方式总结
杀进程方法 | 方法所在类 | 使用层 | 方法描述 |
---|---|---|---|
System.exit(int status) | System | 应用 | 退出虚拟机。status=0为正常退出、非0为异常退出。 |
Process.killProcess(int pid) | Process | 应用、系统 | 调用sendSignal发送信号9,杀死指定pid进程。app调用只能自杀,系统可以杀掉指定pid进程。 |
Process.killProcessGroup(int uid, int pid) | Process | 系统 | 杀掉pid所在的进程组内的所有进程。 |
killApplicationProcess(String processName, int uid) | AMS | 系统 | 系统uid应用才能调用,binder call到客户端自杀:app.thread.scheduleSuicide(); |
killApplication(String pkg, int appId, int userId, String reason) | AMS | 系统 | 系统uid应用才能调用,会将目标应用强杀,作用于指定用户空间。 |
killAllBackgroundProcesses() | AMS | 系统 | 需要KILL_BACKGROUND_PROCESS权限,杀死系统所有优先级小于等于CACHED进程。 |
killBackgroundProcesses(final String packageName, int userId, String reason) | AMS | 应用、系统 | 需要KILL_BACKGROUND_PROCESS权限,杀死指定package所有优先级小于等于SERVICE进程,作用于指定用户空间。 |
killProcessesBelowForeground(String reason) | AMS | 系统 | 系统uid应用才能调用,杀死系统所有优先级小于FOREGROUND的进程。 |
killPackageDependents(String packageName, int userId) | AMS | 系统 | 需要KILL_UID权限,杀死指定package所有优先级小于等于FOREGROUND进程,作用于指定用户空间。 |
killPids(int[] pids, String pReason, boolean secure) | AMS | 系统 | 系统UID应用才能调用,首先找出所有进程所有worstType(跟adj相关的一个判断值),杀死小于等于这个优先级的进程。很保守的查杀方法,并不保证进程被杀 |
killUid(int appId, int userId, String reason) | AMS | 应用、系统 | 需要KILL_UID权限,杀死UID下所有进程,system_server与native进程除外 |
killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) | AMS | 系统 | 系统发生异常后调用,例如ANR ,多为用户主动触发 |
forceStopPackage(final String packageName, int userId) | AMS | 系统 | 需要FORCE_STOP_PACKAGE权限,杀死应用所有进程,并清除各个进程组件信息,作用于指定用户空间,强杀之后连根拔起,寸草不生。属于终极Kill。 |
注:AMS对应的应用层调用方法在ActivityManager中,通过如下方法获取ActivityManager来调用:
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
二、进程查杀核武器:force stop介绍
2.1 查杀方法:
调用AMS forceStopPackageLocked(final String packageName, int uid, String reason)
2.2 查杀条件:
- forceStop不杀系统persistent进程;
- 当指定用户userId时,不杀其他用户空间的进程;
除此之外,以下情况则必然会成为被杀进程:
- 进程已标记remove=true的进程,则会被杀;
- 进程的pkgDeps中包含该packageName,则会被杀;
- 进程的pkgList中包含该packageName,且该进程与包名所指定的AppId相等则会被杀;
进程的pkgList是在启动组件或者创建进程的过程向该队列添加的,代表的是该应用下有组件运行在该进程。那么pkgDeps是指该进程所依赖的包名,调用ClassLoader的过程添加。
2.3 查杀过程:
- 应用状态:pms.setPackageStoppedState()将应用的状态置为STOP,并且无法通过带有EXCLUDE_STOPPED flag的广播启动进程
- Process: 调用AMS.killPackageProcessesLocked()清理该package所涉及的进程;
- Activity: 调用ASS.finishDisabledPackageActivitiesLocked()清理该package所涉及的Activity;
- Service: 调用AS.bringDownDisabledPackageServicesLocked()清理该package所涉及的Service;
- Provider: 调用AMS.removeDyingProviderLocked()清理该package所涉及的Provider;
- BroadcastRecevier: 调用BQ.cleanupDisabledPackageReceiversLocked()清理该package所涉及的广播
- 发送广播ACTION_PACKAGE_RESTARTED,用于停止已注册的alarm,notification.
当app被force-stop后,90%保活策略都会失效:
- 无法接收到任何普通广播,那么也就常见的监听手机网络状态的变化或者屏幕亮灭的广播来拉起进程肯定是不可行;
- alarm闹钟一并被清理,无法实现定时响起的功能;
- 四大组件以及相关进程都被一一剪除清理,即便多进程架构的app也无法拉起自己;
- 级联诛杀:当app通过ClassLoader加载另一个app,则会在force-stop的过程中会被级联诛杀;
- 生死与共:当app与另个app使用了share uid,在force-stop的过程,任意一方被杀则另一方也被杀,建立起生死与共的强关系。
参考:
http://gityuan.com/2016/10/22/force-stop/
系列文章:
Android进程管理篇(一)-应用进程启动过程
Android进程管理篇(二)-进程查杀方式总结
Android进程管理篇(三)-AMS进程调度
lowmemorykiller总结