基于 Android 7.1.1
源码,分析和总结进程相关的知识!
本文参考:
1 | https://developer.android.com/guide/components/processes-and-threads.html |
1 进程的重要性层次
进程的重要性层次一共有 5
级,以下的部分内容截取自 Android Developer Guide
!
From Android Developer Guide
【前台进程 Foreground Process】
定义:用户当前操作所必需的进程。
- 如果一个进程满足以下任一条件,即视为前台进程:
- 托管用户正在交互的
Activity
。(即已调用Activity
的onResume()
方法) - 托管某个
Service
,后者绑定到用户正在交互的Activity
。 - 托管正在 “前台” 运行的
Service
。(服务已调用startForeground()
) - 托管正执行一个生命周期回调的
Service
。(比如:onCreate()
,onStart()
或onDestroy()
) - 托管正执行其
onReceive()
方法的BroadcastReceiver
- 托管用户正在交互的
通常,在任意给定时间前台进程都为数不多。前台进程的优先级最高,只有在内存不足,万不得已的时候,系统才会杀掉他们!
【可见进程 Visible Process】
定义:没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。
- 如果一个进程满足以下任一条件,即视为可见进程:
- 托管不在前台、但仍对用户可见的
Activity
(已调用其onPause()
方法)。- 例如,如果前台
Activity
启动了一个对话框,允许在其后显示上一个Activity
,则有可能会发生这种情况。
- 例如,如果前台
- 托管绑定到可见(或前台)
Activity
的Service
。
- 托管不在前台、但仍对用户可见的
可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
【服务进程 Service Process】
定义:正在运行已使用 startService()
方法启动的服务且不属于上述两个更高类别进程的进程,那就属于服务进程!
可以看到管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
【后台进程 Background Process】
定义:包含目前对用户不可见的 Activity
的进程(已调用 Activity
的 onStop()
方法)。
这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。
通常会有很多后台进程在运行,因此它们会保存在 LRU
(最近最少使用)列表中,以确保包含用户最近查看的 Activity
的进程最后一个被终止。
如果某个 Activity
正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity
时,Activity
会恢复其所有可见状态。
【空进程 Empty Process】
定义:不含任何活动应用组件的进程。
保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
End From
通过 Android developer guide
我们能可以知道进程优先级的 5
分类以及其满足的条件,这里我用一张思维导图简单的总结一下:
注意:这只是一个粗略的划分。其实,在系统的内部实现中,优先级远不止这么五种。
2 进程的优先级和状态
在 ActivityManager.java
中,我们可以通过一个方法来获得系统中所有正在运行中的应用进程的信息:
1 | public List<RunningAppProcessInfo> getRunningAppProcesses() { |
该方法会返回一个 List
列表,每一个进程都被封装成了一个 RunningAppProcessInfo
对象,RunningAppProcessInfo
中有几个重要的成员变量,用于表示进程的重要性和状态;
1 | public int importance; |
其中,processState
表示的是进程的状态,系统是通过这个值来动态调节进程的优先级的;importance
则是进程的重要级别,它是系统暴露给外部的参数,用于获得自身或者其他一个应用进程的重要性级别,下面我们来看看二者的关系和定义!
2.1 进程的优先级
首先,来看看 importance
,其表示进程的重要性级别,取值有如下的 10
种,定义在 ActivityManager.java
中!
1 | // 该进程持有前台 UI 界面,该 UI 界面正在和用户交互! |
2.2 进程的状态
接着,我们来看看 processState
,其表示进程的状态,其取值范围有如下的 17
种,同样定义在 ActivityManager.java
中!
进程的状态是从 android
系统管理角度进行的分级,和 lmk
的分级不同!
1 | // 进程不存在! |
我们知道,每一个进程在系统中都有一个 ProcessRecord
对象与之对应,其内部封装着该进程的数据和组件信息,ProcessRecord
也有一些成员变量,其取值也是上面的这 17
种!
1 | int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state |
ActivityManagerService
就是通过这些变量来设置和调整进程的状态的,这个我们后面再看!
2.3 进程优先级和状态的转换
在系统中 processState
和 importance
是有相应的映射和转换关系的,其映射方法的定义在 ActivityManager.java
中!
1 |
|
最终的映射函数在 RunningAppProcessInfo.procStateToImportance
:
1 | public static int procStateToImportance(int procState) { |
通过该方法,我们可以知道,某个应用进程所属的重要性级别了!
这里不解的是,对应关系中忽略掉了一些 IMPORTANCE
级别,不只是为什么!
3 进程的 oomAdj 值
说到 oomAdj
,我们就要谈到 Android
中的一个很重要的机制 Low Memory Killer
,也叫做低内存杀手!对于 Low Memory Killer
,我后面会单独写一篇文章来分析和总结!
Low Memory Killer
基于 Linux
的 OOM
机制,在 Linux
中,内存是以页面为单位分配的,当申请页面分配时如果内存不足会通过以下流程选择 bad
进程来杀掉从而释放内存:
1 | alloc_pages -> out_of_memory() -> select_bad_process() -> badness() |
而 Low Memory Killer
杀进程依据就是进程的 oom_adj
值,oom_adj
越小越不容易被杀死,对于 oomAdj
值,定义在 ProcessList.java
中;
1 | // 初始化值 |
我们在前面知道了进程的重要性级别和进程的状态的映射关系,那么对于进程的状态和进程的 oomAdj
之间是否也有一定的联系呢?这里就要谈到 oomAdj
的调度算法,我会单独开一篇文章来分析!
接下来,我介绍下 ProcessRecord
中和 oomAdj
相关的几个重要变量,我们后续分析 oomAdj
的时候会遇到:
1 | int maxAdj; // 该进程最大的 Adj,进程的 adj 的设定不能超过该值 |
对于 low memory killer
,当系统的可用内存不够的时候,他会根据一定的策略来杀掉进程,释放内存,针对 low memory killer
我后续也会单独写一篇博文来分析!
4 ActivityManager 相关接口
1 | /** @hide Should this process state be considered a background state? */ |
该方法用来判断,一个进程是否是后台进程!!
http://melove.net/blog/2017/03/android-daemon-service-1488942411000.html
http://www.cnblogs.com/angeldevil/category/336548.html
http://blog.csdn.net/ccjhdopc/article/details/52818012
http://blog.csdn.net/ccjhdopc/article/details/52818012
[1]: