前言
Android 8.0 / 8.1是目前 Android 最新的正式發行版智能手機操做系統,2017年3月21日 Google 爲開發者推出了新的 Android O 首個開發者預覽版,2017 Google I/O 開發者大會上發佈了第二個Android O開發者預覽。2017年8月22日,谷歌正式發佈了Android 8.0的正式版,其正式名稱爲:Android Oreo(奧利奧)。2017年12月5日谷歌正式發佈了Android 8.1的正式版。在最近的 Android 版本更新中,能夠看得出來,Google 已經更加註重 Android 的流暢性和續航能力等性能,這個傾斜會讓 Android 的用戶體驗變得愈來愈好。html
聽說谷歌重寫的Android的底層源碼,我在查看進程時就發現了一些顯著的不一樣,固然我沒有使用實機操做,不知道這個現象是否正常。如下爲我平常使用的Sony Xperia Z5 Premium 搭載 Android 7.1.1 和AVD上的一個Android 8.0 的虛擬在adb shell中查看進程的不一樣之處。java
能夠看到AVD已經再也不顯示 root system 等USER的進程了,表頭也發生了變化,sh進程NAME值爲sh,而非7.0的/system/bin/sh。linux
Android系統架構
Android 操做系統是一個軟件組件的棧,在架構圖中它大體能夠分爲五個部分和四個主要層。android
Linux內核
在全部層的最底下是 Linux - 包括大約115個補丁的 Linux 3.6。它提供了基本的系統功能,好比進程管理,內存管理,設備管理(如攝像頭,鍵盤,顯示器)。同時,內核處理全部 Linux 所擅長的工做,如網絡和大量的設備驅動,從而避免兼容大量外圍硬件接口帶來的不便。git
程序庫
在 Linux 內核層的上面是一系列程序庫的集合,包括開源的 Web 瀏覽器引擎 Webkit ,知名的 libc 庫,用於倉庫存儲和應用數據共享的 SQLite 數據庫,用於播放、錄製音視頻的庫,用於網絡安全的 SSL 庫等。web
Android程序庫
這個類別包括了專門爲 Android 開發的基於 Java 的程序庫。這個類別程序庫的示例包括應用程序框架庫,如用戶界面構建,圖形繪製和數據庫訪問。一些 Android 開發者可用的 Android 核心程序庫總結以下:算法
- android.app - 提供應用程序模型的訪問,是全部 Android 應用程序的基石。
- android.content - 方便應用程序之間,應用程序組件之間的內容訪問,發佈,消息傳遞。
- android.database - 用於訪問內容提供者發佈的數據,包含 SQLite 數據庫管理類。
- android.opengl - OpenGL ES 3D 圖片渲染 API 的 Java 接口。
- android.os - 提供應用程序訪問標註操做系統服務的能力,包括消息,系統服務和進程間通訊。
- android.text - 在設備顯示上渲染和操做文本。
- android.view - 應用程序用戶界面的基礎構建塊。
- android.widget - 豐富的預置用戶界面組件集合,包括按鈕,標籤,列表,佈局管理,單選按鈕等。
- android.webkit - 一系列類的集合,容許爲應用程序提供內建的 Web 瀏覽能力。
看過了 Android 運行層內的基於 Java 的核心程序庫,是時候關注一下 Android 軟件棧中的基於 C/C++ 的程序庫。shell
Android運行時
這是架構中的第三部分,自下而上的第二層。這個部分提供名爲 Dalvik 虛擬機的關鍵組件,相似於 Java 虛擬機,但專門爲 Android 設計和優化。數據庫
Dalvik 虛擬機使得能夠在 Java 中使用 Linux 核心功能,如內存管理和多線程。Dalvik 虛擬機使得每個 Android 應用程序運行在本身獨立的虛擬機進程。瀏覽器
Android 運行時同時提供一系列核心的庫來爲 Android 應用程序開發者使用標準的 Java 語言來編寫 Android 應用程序。
應用框架
應用框架層以 Java 類的形式爲應用程序提供許多高級的服務。應用程序開發者被容許在應用中使用這些服務。
- 活動管理者 - 控制應用程序生命週期和活動棧的全部方面。
- 內容提供者 - 容許應用程序之間發佈和分享數據。
- 資源管理器 - 提供對非代碼嵌入資源的訪問,如字符串,顏色設置和用戶界面佈局。
- 通知管理器 - 容許應用程序顯示對話框或者通知給用戶。
- 視圖系統 - 一個可擴展的視圖集合,用於建立應用程序用戶界面。
應用程序
頂層中有全部的 Android 應用程序。你寫的應用程序也將被安裝在這層。這些應用程序包括通信錄,瀏覽器,遊戲等。
Android進程
查看Android進程
Android是基於Linux的,可是沒有terminal因此咱們查看Android進程須要使用adb中的adb shell進入手機,再使用ps指令來查看,如前言所示。
Android進程
當某個應用組件啓動且該應用沒有運行其餘任何組件時,Android 系統會使用單個執行線程爲應用啓動新的 Linux 進程。
默認狀況下,同一應用的全部組件均在相同的進程中運行,且大多數應用都不會改變這一點。 可是,若是您發現須要控制某個組件所屬的進程,則可在清單文件中執行此操做。
若是內存不足,而其餘爲用戶提供更緊急服務的進程又須要內存時,Android 可能會決定在某一時刻關閉某一進程。在被終止進程中運行的應用組件也會隨之銷燬。 當這些組件須要再次運行時,系統將爲它們重啓進程。
決定終止哪一個進程時,Android 系統將權衡它們對用戶的相對重要程度。例如,相對於託管可見 Activity 的進程而言,它更有可能關閉託管屏幕上再也不可見的 Activity 的進程。 所以,是否終止某個進程的決定取決於該進程中所運行組件的狀態。
進程生命週期
Android 系統將盡可能長時間地保持應用進程,但爲了新建進程或運行更重要的進程,最終須要移除舊進程來回收內存。 爲了肯定保留或終止哪些進程,系統會根據進程中正在運行的組件以及這些組件的狀態,將每一個進程放入「重要性層次結構」中。 必要時,系統會首先消除重要性最低的進程,而後是重要性略遜的進程,依此類推,以回收系統資源。
Android系統共有五種等級的進程
重要性層次結構一共有 5 級。如下列表按照重要程度列出了各種進程(第一個進程最重要,將是最後一個被終止的進程):
- 前臺進程
用戶當前操做所必需的進程。若是一個進程知足如下任一條件,即視爲前臺進程:
一般,在任意給定時間前臺進程都爲數很少。只有在內存不足以支持它們同時繼續運行這一萬不得已的狀況下,系統纔會終止它們。 此時,設備每每已達到內存分頁狀態,所以須要終止一些前臺進程來確保用戶界面正常響應。
- 可見進程
沒有任何前臺組件、但仍會影響用戶在屏幕上所見內容的進程。 若是一個進程知足如下任一條件,即視爲可見進程:
- 託管不在前臺、但仍對用戶可見的
Activity
(已調用其 onPause()
方法)。例如,若是前臺 Activity 啓動了一個對話框,容許在其後顯示上一 Activity,則有可能會發生這種狀況。
- 託管綁定到可見(或前臺)Activity 的
Service
。
可見進程被視爲是極其重要的進程,除非爲了維持全部前臺進程同時運行而必須終止,不然系統不會終止這些進程。
- 服務進程
正在運行已使用 startService()
方法啓動的服務且不屬於上述兩個更高類別進程的進程。儘管服務進程與用戶所見內容沒有直接關聯,可是它們一般在執行一些用戶關心的操做(例如,在後臺播放音樂或從網絡下載數據)。所以,除非內存不足以維持全部前臺進程和可見進程同時運行,不然系統會讓服務進程保持運行狀態。
- 後臺進程
包含目前對用戶不可見的 Activity 的進程(已調用 Activity 的 onStop()
方法)。這些進程對用戶體驗沒有直接影響,系統可能隨時終止它們,以回收內存供前臺進程、可見進程或服務進程使用。 一般會有不少後臺進程在運行,所以它們會保存在 LRU (最近最少使用)列表中,以確保包含用戶最近查看的 Activity 的進程最後一個被終止。若是某個 Activity 正確實現了生命週期方法,並保存了其當前狀態,則終止其進程不會對用戶體驗產生明顯影響,由於當用戶導航回該 Activity 時,Activity 會恢復其全部可見狀態。 有關保存和恢復狀態的信息,請參閱 Activity文檔。
- 空進程
不含任何活動應用組件的進程。保留這種進程的的惟一目的是用做緩存,以縮短下次在其中運行組件所需的啓動時間。 爲使整體系統資源在進程緩存和底層內核緩存之間保持平衡,系統每每會終止這些進程。
進程優先級的定義
OOM adjustments與 Process Importance決定了進程在調用中的優先級。
ADJ值定義在frameworks\base\services\core\java\com\android\server\am\ProcessList.java中
// OOM adjustments for processes in various states:
// Uninitialized value for any major or minor adj fields
static final int INVALID_ADJ = -10000;
// Adjustment used in certain places where we don't know it yet.
// (Generally this is something that is going to be cached, but we
// don't know the exact value in the cached range to assign yet.)
static final int UNKNOWN_ADJ = 1001;
// This is a process only hosting activities that are not visible,
// so it can be killed without any disruption.
static final int CACHED_APP_MAX_ADJ = 906;
static final int CACHED_APP_MIN_ADJ = 900;
// The B list of SERVICE_ADJ -- these are the old and decrepit
// services that aren't as shiny and interesting as the ones in the A list.
static final int SERVICE_B_ADJ = 800;
// This is the process of the previous application that the user was in.
// This process is kept above other things, because it is very common to
// switch back to the previous app. This is important both for recent
// task switch (toggling between the two top recent apps) as well as normal
// UI flow such as clicking on a URI in the e-mail app to view in the browser,
// and then pressing back to return to e-mail.
static final int PREVIOUS_APP_ADJ = 700;
// This is a process holding the home application -- we want to try
// avoiding killing it, even if it would normally be in the background,
// because the user interacts with it so much.
static final int HOME_APP_ADJ = 600;
// This is a process holding an application service -- killing it will not
// have much of an impact as far as the user is concerned.
static final int SERVICE_ADJ = 500;
// This is a process with a heavy-weight application. It is in the
// background, but we want to try to avoid killing it. Value set in
// system/rootdir/init.rc on startup.
static final int HEAVY_WEIGHT_APP_ADJ = 400;
// This is a process currently hosting a backup operation. Killing it
// is not entirely fatal but is generally a bad idea.
static final int BACKUP_APP_ADJ = 300;
// This is a process only hosting components that are perceptible to the
// user, and we really want to avoid killing them, but they are not
// immediately visible. An example is background music playback.
static final int PERCEPTIBLE_APP_ADJ = 200;
// This is a process only hosting activities that are visible to the
// user, so we'd prefer they don't disappear.
static final int VISIBLE_APP_ADJ = 100;
static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1;
// This is the process running the current foreground app. We'd really
// rather not kill it!
static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to,
// and indicated it is important.
static final int PERSISTENT_SERVICE_ADJ = -700;
// This is a system persistent process, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int PERSISTENT_PROC_ADJ = -800;
// The system process runs at the default adjustment.
static final int SYSTEM_ADJ = -900;
// Special code for native processes that are not being managed by the system (so
// don't have an oom adj assigned by the system).
static final int NATIVE_ADJ = -1000;
ADJ值越小則優先度越高,例如INVALID和NATIVE的ADJ值在Android 8.0中爲-10000和-1000,優先度最高,系統不會去關閉它。緊隨其後的是SYSTEM,ADJ值爲-900。
ADJ值 |
類型 |
-10000 |
INVALID 未定義 |
-1000 |
NATIVE 本機持有的特殊代碼 |
-900 |
SYSTEM |
-800 |
PERSISTENT_PROC 系統持續進程(電話) |
-700 |
PERSISTENT_SERVICE 系統服務進程 |
0 |
FOREGROUND_APP 前臺應用 |
100 |
VISIBLE_APP 可見應用 |
200 |
PERCEPTIBLE_APP 後臺應用 |
300 |
BACKUP_APP 備份進程 |
400 |
HEAVY_WEIGHT_APP 重量級後臺進程 |
500 |
SERVICE 服務進程 |
600 |
HOME_APP 主進程 |
700 |
PREVIOUS_APP 上一個進程 |
800 |
SERVICE_B 舊的服務進程B列表 |
900 |
CACHED_APP_MIN |
906 |
CACHED_APP_MAX |
1001 |
UNKNOWN |
99(PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1) |
VISIBLE_APP_LAYER_MAX |
一 : 前臺進程 (Active Process): oom_adj爲0。
前臺進程包括 : 1 : 活動 正在前臺接收用戶輸入
2:活動、服務與廣播接收器正在執行一個onReceive事件的處理函數
3: 服務正在運行 onStart、onCreate或onDestroy事件處理函數。
二 : 已啓動服務的進程(Started Service Process) :oom_adj值爲0,這類進程包含一個已啓動的服務。 服務並不直接與用戶輸入交互,所以服務的優先級
低於可見活動的優先級,可是,已啓動服務的進程任被認爲是前臺進程,只有在活動以及可見活動須要資源時,已啓動服務的進程纔會被殺死。
三 :可見進程 (Visible Process): oom_adj 爲 100。活動是可見的,但並不在前臺,或者不響應用戶的輸入。例如,活動被非全屏或者透明的活動所遮擋。
//如下爲舊版本
四 :後臺進程 (Backgroud Process): oom_adj 值爲 2,這類進程不包含任何可見的活動與啓動的服務。一般大量後臺進程存在時,系統會採用(last-seen-first-kill)後見先殺的方式,釋放資源爲前臺進程使用。
五 :主界面 (home process): oom_adj 爲 4
六 :隱藏進程 (hidden process): oom_adj爲 7
七 :內容提供者 (content provider):oom_adj 爲 14
八 :空進程 (Empty process):oom_adj爲 15
Process Importance定義在frameworks/base/core/java/android/app/ActivityManager.java類中:
/**
* Constant for {@link #importance}: This process is running the
* foreground UI; that is, it is the thing currently at the top of the screen
* that the user is interacting with.
*/
public static final int IMPORTANCE_FOREGROUND = 100;
/**
* Constant for {@link #importance}: This process is running a foreground
* service, for example to perform music playback even while the user is
* not immediately in the app. This generally indicates that the process
* is doing something the user actively cares about.
*/
public static final int IMPORTANCE_FOREGROUND_SERVICE = 125;
/**
* Constant for {@link #importance}: This process is running the foreground
* UI, but the device is asleep so it is not visible to the user. This means
* the user is not really aware of the process, because they can not see or
* interact with it, but it is quite important because it what they expect to
* return to once unlocking the device.
*/
public static final int IMPORTANCE_TOP_SLEEPING = 150;
/**
* Constant for {@link #importance}: This process is running something
* that is actively visible to the user, though not in the immediate
* foreground. This may be running a window that is behind the current
* foreground (so paused and with its state saved, not interacting with
* the user, but visible to them to some degree); it may also be running
* other services under the system's control that it inconsiders important.
*/
public static final int IMPORTANCE_VISIBLE = 200;
/**
* Constant for {@link #importance}: {@link #IMPORTANCE_PERCEPTIBLE} had this wrong value
* before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK,
* the value of {@link #IMPORTANCE_PERCEPTIBLE} has been fixed.
*
* <p>The system will return this value instead of {@link #IMPORTANCE_PERCEPTIBLE}
* on Android versions below {@link Build.VERSION_CODES#O}.
*
* <p>On Android version {@link Build.VERSION_CODES#O} and later, this value will still be
* returned for apps with the target API level below {@link Build.VERSION_CODES#O}.
* For apps targeting version {@link Build.VERSION_CODES#O} and later,
* the correct value {@link #IMPORTANCE_PERCEPTIBLE} will be returned.
*/
public static final int IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
/**
* Constant for {@link #importance}: This process is not something the user
* is directly aware of, but is otherwise perceptible to them to some degree.
*/
public static final int IMPORTANCE_PERCEPTIBLE = 230;
/**
* Constant for {@link #importance}: {@link #IMPORTANCE_CANT_SAVE_STATE} had
* this wrong value
* before {@link Build.VERSION_CODES#O}. Since the {@link Build.VERSION_CODES#O} SDK,
* the value of {@link #IMPORTANCE_CANT_SAVE_STATE} has been fixed.
*
* <p>The system will return this value instead of {@link #IMPORTANCE_CANT_SAVE_STATE}
* on Android versions below {@link Build.VERSION_CODES#O}.
*
* <p>On Android version {@link Build.VERSION_CODES#O} after, this value will still be
* returned for apps with the target API level below {@link Build.VERSION_CODES#O}.
* For apps targeting version {@link Build.VERSION_CODES#O} and later,
* the correct value {@link #IMPORTANCE_CANT_SAVE_STATE} will be returned.
*
* @hide
*/
public static final int IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
/**
* Constant for {@link #importance}: This process is running an
* application that can not save its state, and thus can't be killed
* while in the background.
* @hide
*/
public static final int IMPORTANCE_CANT_SAVE_STATE= 270;
/**
* Constant for {@link #importance}: This process is contains services
* that should remain running. These are background services apps have
* started, not something the user is aware of, so they may be killed by
* the system relatively freely (though it is generally desired that they
* stay running as long as they want to).
*/
public static final int IMPORTANCE_SERVICE = 300;
/**
* Constant for {@link #importance}: This process process contains
* cached code that is expendable, not actively running any app components
* we care about.
*/
public static final int IMPORTANCE_CACHED = 400;
/**
* @deprecated Renamed to {@link #IMPORTANCE_CACHED}.
*/
public static final int IMPORTANCE_BACKGROUND = IMPORTANCE_CACHED;
/**
* Constant for {@link #importance}: This process is empty of any
* actively running code.
* @deprecated This value is no longer reported, use {@link #IMPORTANCE_CACHED} instead.
*/
@Deprecated
public static final int IMPORTANCE_EMPTY = 500;
/**
* Constant for {@link #importance}: This process does not exist.
*/
public static final int IMPORTANCE_GONE = 1000;
IMPORTANCE值也是越小優先度越高。
IMPORTANCE_FOREGROUND 意味着這個進程正在運行前臺UI,也就是說,它是當前在屏幕頂部的東西,用戶正在進行交互的而進程,即以前提到的前臺進程。
IMPORTANCE_FOREGROUND_SERVICE前臺服務,即便用戶不是在應用中時也執行音樂播放,這通常表示該進程正在作用戶積極關心的事情。
在這裏咱們發現了一個Android 8.0不一樣以往的地方新增了IMPORTANCE_CACHED = 400的定義,然後臺進程IMPORTANCE_BACKGROUND值與其相同。
IMPORTANCE值 |
屬性 |
100 |
FOREGROUND |
125 |
FOREGROUND_SERVICE |
130 |
PERCEPTIBLE_PRE_26 |
170 |
CANT_SAVE_STATE_PRE_26 |
150 |
TOP_SLEEPING |
200 |
VISIBLE |
230 |
PERCEPTIBLE |
270 |
CANT_SAVE_STATE |
300 |
SERVICE |
400 |
CACHED & BACKGROUND |
500 |
EMPTY |
1000 |
GONE |
進程回收機制
這裏參考自穿褲衩闖天下 的文章《Android 守護進程的實現方式》
Android
的Low Memory Killer
基於Linux
的OOM
機制,在Linux
中,內存是以頁面爲單位分配的,當申請頁面分配時若是內存不足會經過如下流程選擇bad進程來殺掉從而釋放內存:
alloc_pages -> out_of_memory() -> select_bad_process() -> badness()
在Low Memory Killer
中經過進程的oom_adj
與佔用內存的大小決定要殺死的進程,oom_adj
越小越不容易被殺死;
Low Memory Killer Driver
在用戶空間指定了一組內存臨界值及與之一一對應的一組oom_adj
值,當系統剩餘內存位於內存臨界值中的一個範圍內時,若是一個進程的oom_adj
值大於或等於這個臨界值對應的oom_adj
值就會被殺掉。
下邊是表示Process State
(即老版本里的OOM_ADJ
)數值對照表,數值越大,重要性越低,在新版SDK中已經在android
層去除了小於0的進程狀態
// Path:SDK/sources/android-25/android/app/ActivityManager#RunningAppProcessInfo.java
// 進程不存在。
public static final int PROCESS_STATE_NONEXISTENT = -1;
// 進程是一個持久的系統進程,通常指當前 UI 進程
public static final int PROCESS_STATE_PERSISTENT = 0;
// 進程是一個持久的系統進程,正在作和 UI 相關的操做,但不直接顯示
public static final int PROCESS_STATE_PERSISTENT_UI = 1;
// 進程正在託管當前的頂級活動。請注意,這涵蓋了用戶可見的全部活動。
public static final int PROCESS_STATE_TOP = 2;
// 進程因爲系統綁定而託管前臺服務。
public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
// 進程正在託管前臺服務。
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
// 與{@link #PROCESS_STATE_TOP}相同,但設備處於睡眠狀態。
public static final int PROCESS_STATE_TOP_SLEEPING = 5;
// 進程對用戶很重要,是他們知道的東西
public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
// 進程對用戶很重要,但不是他們知道的
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
// 進程在後臺運行備份/恢復操做
public static final int PROCESS_STATE_BACKUP = 8;
// 進程在後臺,但咱們不能恢復它的狀態,因此咱們想盡可能避免殺死它,否則這個而進程就丟了
public static final int PROCESS_STATE_HEAVY_WEIGHT = 9;
// 進程在後臺運行一個服務,與oom_adj不一樣,此級別用於正常運行在後臺狀態和執行操做狀態。
public static final int PROCESS_STATE_SERVICE = 10;
// 進程在後臺運行一個接收器,注意,從oom_adj接收器的角度來看,在較高的前臺級運行,可是對於咱們的優先級,這不是必需的,而且將它們置於服務之下意味着當它們接收廣播時,一些進程狀態中的更少的改變。
public static final int PROCESS_STATE_RECEIVER = 11;
// 進程在後臺,但主持家庭活動
public static final int PROCESS_STATE_HOME = 12;
// 進程在後臺,但託管最後顯示的活動
public static final int PROCESS_STATE_LAST_ACTIVITY = 13;
// 進程正在緩存以供之後使用,幷包含活動
public static final int PROCESS_STATE_CACHED_ACTIVITY = 14;
// 進程正在緩存供之後使用,而且是包含活動的另外一個緩存進程的客戶端
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
// 進程正在緩存以供之後使用,而且爲空
public static final int PROCESS_STATE_CACHED_EMPTY = 16;
在Android 8.0 中是這樣的,增長了1七、18兩個值四個STATE:PROCESS_STATE_CACHED_EMPTY、PROCESS_STATE_NONEXISTENT、MIN_PROCESS_STATE、MAX_PROCESS_STATE。
/** @hide Not a real process state. */
public static final int PROCESS_STATE_UNKNOWN = -1;
/** @hide Process is a persistent system process. */
public static final int PROCESS_STATE_PERSISTENT = 0;
/** @hide Process is a persistent system process and is doing UI. */
public static final int PROCESS_STATE_PERSISTENT_UI = 1;
/** @hide Process is hosting the current top activities. Note that this covers
* all activities that are visible to the user. */
public static final int PROCESS_STATE_TOP = 2;
/** @hide Process is hosting a foreground service due to a system binding. */
public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
/** @hide Process is hosting a foreground service. */
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
/** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
public static final int PROCESS_STATE_TOP_SLEEPING = 5;
/** @hide Process is important to the user, and something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
/** @hide Process is in the background transient so we will try to keep running. */
public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
/** @hide Process is in the background running a backup/restore operation. */
public static final int PROCESS_STATE_BACKUP = 9;
/** @hide Process is in the background, but it can't restore its state so we want
* to try to avoid killing it. */
public static final int PROCESS_STATE_HEAVY_WEIGHT = 10;
/** @hide Process is in the background running a service. Unlike oom_adj, this level
* is used for both the normal running in background state and the executing
* operations state. */
public static final int PROCESS_STATE_SERVICE = 11;
/** @hide Process is in the background running a receiver. Note that from the
* perspective of oom_adj receivers run at a higher foreground level, but for our
* prioritization here that is not necessary and putting them below services means
* many fewer changes in some process states as they receive broadcasts. */
public static final int PROCESS_STATE_RECEIVER = 12;
/** @hide Process is in the background but hosts the home activity. */
public static final int PROCESS_STATE_HOME = 13;
/** @hide Process is in the background but hosts the last shown activity. */
public static final int PROCESS_STATE_LAST_ACTIVITY = 14;
/** @hide Process is being cached for later use and contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY = 15;
/** @hide Process is being cached for later use and is a client of another cached
* process that contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16;
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 17;
/** @hide Process does not exist. */
public static final int PROCESS_STATE_NONEXISTENT = 18;
/** @hide The lowest process state number */
public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
/** @hide The highest process state number */
public static final int MAX_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
Process State
(即老版本的OOM_ADJ
)與Process Importance
對應關係,這個方法也是在ActivityManager.java
類中,有了這個關係,就知道能夠知道咱們的應用處於哪一個級別,對於咱們後邊優化有個很好地參考
/**
* Path:SDK/sources/android-25/android/app/ActivityManager#RunningAppProcessInfo.java
* 這裏在Android8.0中沒有發生變化
* 經過這個方法,將Linux底層的 OOM_ADJ級別碼和 android 層面的進程重要程度聯繫了起來
*/
public static int procStateToImportance(int procState) {
if (procState == PROCESS_STATE_NONEXISTENT) {
return IMPORTANCE_GONE;
} else if (procState >= PROCESS_STATE_HOME) {
return IMPORTANCE_BACKGROUND;
} else if (procState >= PROCESS_STATE_SERVICE) {
return IMPORTANCE_SERVICE;
} else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
return IMPORTANCE_CANT_SAVE_STATE;
} else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
return IMPORTANCE_PERCEPTIBLE;
} else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
return IMPORTANCE_VISIBLE;
} else if (procState >= PROCESS_STATE_TOP_SLEEPING) {
return IMPORTANCE_TOP_SLEEPING;
} else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
return IMPORTANCE_FOREGROUND_SERVICE;
} else {
return IMPORTANCE_FOREGROUND;
}
}
通常狀況下,設備端進程被幹掉有一下幾種狀況
進程結束場景 |
結束方式 |
影響範圍 |
Android 系統自身內存回收機制 |
Low Memory Killer |
Process State 數值從大到小 |
第三方管理程序清理進程 無 Root 權限 |
killBackgroundProcess |
Process State 數值大於6進程 |
第三方管理程序清理進程 有 Root 權限 |
force-stop or Kill |
除當前前臺進程外全部非系統進程 |
Rom 清除進程(用戶手動清理) |
force-stop or Kill |
全部非系統進程 |
用戶手動強制結束 |
force-stop |
第三方應用以及非 System 進程 |
Android進程狀態轉換
這裏參考了一篇CSDN的文章
Android應用進程啓動
當咱們在Launcher桌面上點擊一個應用的圖標時,固然Launcher啓動以後,已經把桌面上每一個圖標對應的信息都封裝好了,用戶點擊以後,Launcher進程就會經過Binder進程間通訊機制調用startActivity的方式去打開目標進程的入口Activity,指令傳達到ActivityManagerService當中時,AMS會去檢測當有的應用進程是否已經啓動,若是沒有啓動,那麼就會先將當前的目標進程啓動起來,啓動目標進程是經過調用startProcessLocked方法來完成的。
方法的實如今ActivityManagerService類中,目錄路徑爲frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java,startProcessLocked方法的源碼以下:
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
null /* entryPoint */, null /* entryPointArgs */);
}
該方法就是直接調用另外一個重載方法來實如今,該重載方法的源碼以下:
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
checkTime(startTime, "startProcess: removing from pids map");
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
checkTime(startTime, "startProcess: done removing from pids map");
app.setPid(0);
}
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
"startProcessLocked removing on hold: " + app);
mProcessesOnHold.remove(app);
checkTime(startTime, "startProcess: starting to update cpu stats");
updateCpuStats();
checkTime(startTime, "startProcess: done updating cpu stats");
try {
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
checkTime(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName,
MATCH_DEBUG_TRIAGED_MISSING, app.userId);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
*/
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[3];
} else {
gids = new int[permGids.length + 3];
System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
checkTime(startTime, "startProcess: building args");
if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0;
}
if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags & ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
uid = 0;
}
}
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_JDWP;
debugFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
mSafeMode == true) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
String genDebugInfoProperty = SystemProperties.get("debug.generate-debug-info");
if ("true".equals(genDebugInfoProperty)) {
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
if (mNativeDebuggingApp != null && mNativeDebuggingApp.equals(app.processName)) {
// Enable all debug flags required by the native debugger.
debugFlags |= Zygote.DEBUG_ALWAYS_JIT; // Don't interpret anything
debugFlags |= Zygote.DEBUG_GENERATE_DEBUG_INFO; // Generate debug info
debugFlags |= Zygote.DEBUG_NATIVE_DEBUGGABLE; // Disbale optimizations
mNativeDebuggingApp = null;
}
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
if (new File(wrapperFileName).exists()) {
invokeWith = "/system/bin/logwrapper " + wrapperFileName;
}
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
if (requiredAbi == null) {
requiredAbi = Build.SUPPORTED_ABIS[0];
}
String instructionSet = null;
if (app.info.primaryCpuAbi != null) {
instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
}
app.gids = gids;
app.requiredAbi = requiredAbi;
app.instructionSet = instructionSet;
// the per-user SELinux context must be set
if (TextUtils.isEmpty(app.info.seInfoUser)) {
Slog.wtf(TAG, "SELinux tag not defined",
new IllegalStateException("SELinux tag not defined for "
+ app.info.packageName + " (uid " + app.uid + ")"));
}
final String seInfo = app.info.seInfo
+ (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
checkTime(startTime, "startProcess: returned from zygote!");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
checkTime(startTime, "startProcess: done updating battery stats");
EventLog.writeEvent(EventLogTags.AM_PROC_START,
UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
try {
AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
seInfo, app.info.sourceDir, startResult.pid);
} catch (RemoteException ex) {
// Ignore
}
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
checkTime(startTime, "startProcess: building log message");
StringBuilder buf = mStringBuilder;
buf.setLength(0);
buf.append("Start proc ");
buf.append(startResult.pid);
buf.append(':');
buf.append(app.processName);
buf.append('/');
UserHandle.formatUid(buf, uid);
if (!isActivityProcess) {
buf.append(" [");
buf.append(entryPoint);
buf.append("]");
}
buf.append(" for ");
buf.append(hostingType);
if (hostingNameStr != null) {
buf.append(" ");
buf.append(hostingNameStr);
}
Slog.i(TAG, buf.toString());
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;
checkTime(startTime, "startProcess: starting to update pids map");
ProcessRecord oldApp;
synchronized (mPidsSelfLocked) {
oldApp = mPidsSelfLocked.get(startResult.pid);
}
// If there is already an app occupying that pid that hasn't been cleaned up
if (oldApp != null && !app.isolated) {
// Clean up anything relating to this pid first
Slog.w(TAG, "Reusing pid " + startResult.pid
+ " while app is still mapped to it");
cleanUpApplicationRecordLocked(oldApp, false, false, -1,
true /*replacingPid*/);
}
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
checkTime(startTime, "startProcess: done updating pids map");
} catch (RuntimeException e) {
Slog.e(TAG, "Failure starting process " + app.processName, e);
// Something went very wrong while trying to start this process; one
// common case is when the package is frozen due to an active
// upgrade. To recover, clean up any active bookkeeping related to
// starting this process. (We already invoked this method once when
// the package was initially frozen through KILL_APPLICATION_MSG, so
// it doesn't hurt to use it again.)
forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
}
}
該方法中int uid = app.uid能夠獲取到目標進程的uid,uid是標識目標進程身份的一個整數,它最原始的分配是在應用進程安裝時,由PackageManagerService分配好
關於Android進程模型
在安裝Android應用程序的時候,Android會爲每一個程序分配一個Linux用戶id,並設置相應的權限,這樣其它應用程序就不能訪問此應用程序所擁有的數據和資源了。
默認狀況下,每一個apk運行在它本身的Linux進程中。當須要執行應用程序中的代碼時,Android會啓動一個jvm,即一個新的進程來執行,所以不一樣的apk運行在相互隔離的環境中。
同時,開發者能夠給兩個應用程序分配相同的linux用戶id,這樣他們就能訪問對方所擁有的資源。爲了保留系統資源,擁有相同用戶id的應用程序能夠運行在同一個進程中,共享同一個jvm。
課堂演示
衆所周知,Linux中的全部進程都是有init進程建立並運行的。首先Linux內核啓動,而後在用戶空間中啓動init進程,再啓動其餘系統進程。在系統啓動完成完成後,init將變爲守護進程監視系統其餘進程。Android是基於Linux的操做系統,因此init也是Android系統中用戶空間的第一個進程,它的進程號是1。下面先簡單的看一下init進程的啓動過程。
Android 的線程調度
Android 進程生命週期與ADJ
Android 開發者應該都知道在系統中進程重要性的劃分:
- 前臺進程(Foreground process)
- 可見進程(Visible process)
- 服務進程(Service process)
- 後臺進程(Background process)
- 空進程(Empty process)
相信你們都很清楚,這裏就不作過多的介紹了,不過對於進程重要性是經過哪些操做發生變動的,以及和咱們前面講的 Linux 進程分組又是怎麼關聯和映射上的,是下面要講述的重點。
Android 進程優先級的相關概念
oom_score_adj
級別
對於每個運行中的進程,Linux 內核都經過 proc 文件系統暴露 /proc/[pid]/oom_score_adj
這樣一個文件來容許其餘程序修改指定進程的優先級,這個文件容許的值的範圍是:-1000 ~ +1001之間。值越小,表示進程越重要。當內存很是緊張時,系統便會遍歷全部進程,以肯定哪一個進程須要被殺死以回收內存,此時便會讀取 oom_score_adj
這個文件的值。
PS:在Linux 2.6.36以前的版本中,Linux 提供調整優先級的文件是
/proc/[pid]/oom_adj
。這個文件容許的值的範圍是-17 ~ +15之間。數值越小表示進程越重要。 這個文件在新版的 Linux 中已經廢棄。但你仍然可使用這個文件,當你修改這個文件的時候,內核會直接進行換算,將結果反映到
oom_score_adj
這個文件上。
Android早期版本的實現中也是依賴
oom_adj
這個文件。可是在新版本中,已經切換到使用
oom_score_adj
這個文件。
爲了便於管理,ProcessList.java中預約義了 oom_score_adj
的可能取值,這裏的預約義值也是對應用進程的一種分類。
Lowmemorykiller 根據當前可用內存狀況來進行進程釋放,總設計了6個級別,即上表中「解釋列」加粗的行,即 Lowmemorykiller 的殺進程的6檔,以下:
CACHED_APP_MAX_ADJ
CACHED_APP_MIN_ADJ
BACKUP_APP_ADJ
PERCEPTIBLE_APP_ADJ
VISIBLE_APP_ADJ
FOREGROUND_APP_ADJ
系統內存從很寬裕到不足,Lowmemorykiller 也會相應地從 CACHED_APP_MAX_ADJ
(第1檔)開始殺進程,若是內存還不足,那麼會殺 CACHED_APP_MIN_ADJ
(第2檔),不斷深刻,直到知足內存閾值條件。
ProcessRecord中下面這些屬性反應了 oom_score_adj
的值:
int maxAdj; // Maximum OOM adjustment for this process int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process int curAdj; // Current OOM adjustment for this process int setAdj; // Last set OOM adjustment for this process int verifiedAdj; // The last adjustment that was verified as actually being set
Process State
對應的在 ActivityManager 重定義了 process_state 級別的劃分,Android 系統會在修改進程狀態的同時更新 oom_score_adj
的分級:
在 ProcessRecord 中,記錄了和進程狀態相關的屬性:
int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for
Schedule Group
對應到底層進程分組,除了上面提到的 Process.java
定義的不一樣線程組的定義,同時還爲 Activity manager
定義了一套相似的調度分組,和以前的線程分組定義也存在對應關係:
// Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE static final int SCHED_GROUP_BACKGROUND = 0; // Activity manager's version of Process.THREAD_GROUP_DEFAULT static final int SCHED_GROUP_DEFAULT = 1; // Activity manager's version of Process.THREAD_GROUP_TOP_APP static final int SCHED_GROUP_TOP_APP = 2; // Activity manager's version of Process.THREAD_GROUP_TOP_APP // Disambiguate between actual top app and processes bound to the top app static final int SCHED_GROUP_TOP_APP_BOUND = 3;
在 ProcessRecord 中,也記錄了和調度組相關的屬性:
int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class
Android 進程優先級的變化
咱們知道影響 Android 應用進程優先級變化的是根據 Android
應用組件的生命週期變化相關。Android進程調度之adj算法 裏面羅列了全部會觸發進程狀態發生變化的事件,主要包括:
Actvity
- ActivityStackSupervisor.realStartActivityLocked: 啓動Activity
- ActivityStack.resumeTopActivityInnerLocked: 恢復棧頂Activity
- ActivityStack.finishCurrentActivityLocked: 結束當前Activity
- ActivityStack.destroyActivityLocked: 摧毀當前Activity
Service
位於ActiveServices.java
- realStartServiceLocked: 啓動服務
- bindServiceLocked: 綁定服務(只更新當前app)
- unbindServiceLocked: 解綁服務 (只更新當前app)
- bringDownServiceLocked: 結束服務 (只更新當前app)
- sendServiceArgsLocked: 在bringup或則cleanup服務過程調用 (只更新當前app)
broadcast
- BQ.processNextBroadcast: 處理下一個廣播
- BQ.processCurBroadcastLocked: 處理當前廣播
- BQ.deliverToRegisteredReceiverLocked: 分發已註冊的廣播 (只更新當前app)
ContentProvider
- AMS.removeContentProvider: 移除provider
- AMS.publishContentProviders: 發佈provider (只更新當前app)
- AMS.getContentProviderImpl: 獲取provider (只更新當前app)
Process
位於 ActivityManagerService.java
- setSystemProcess: 建立並設置系統進程
- addAppLocked: 建立persistent進程
- attachApplicationLocked: 進程建立後attach到system_server的過程;
- trimApplications: 清除沒有使用app
- appDiedLocked: 進程死亡
- killAllBackgroundProcesses: 殺死全部後臺進程.即(ADJ>9或removed=true的普通進程)
- killPackageProcessesLocked: 以包名的形式 殺掉相關進程;
這些事件都會直接或間接調用到 ActivityManagerService.java
中的 updateOomAdjLocked
方法來更新進程的優先級,updateOomAdjLocked
先經過 computeOomAdjLocked
方法負責計算進程的優先級,再經過調用 applyOomAdjLocked
應用進程的優先級。
computeOomAdjLocked
computeOomAdjLocked
方法負責計算進程的優先級,總計約700行,執行流程比較清晰,步驟以下,因爲代碼有點多這裏就不貼了,想仔細研究的能夠比着系統源碼看: