開發應用的時候,應該檢查它是否有流暢的使用者體驗,即60fps的幀率。如果由於某種原因丟幀,我們首先要做的就是知道系統在做什麼(造成丟幀的原因)。

Systrace允許你監視和跟蹤Android系統的行為(trace)。它會告訴你係統都在哪些工作上花費時間、CPU週期都用在哪裡,甚至你可以看到每個執行緒、程序在指定時間內都在幹嘛。它同時還會突出觀測到的問題,從垃圾回收到渲染內容都可能是問題物件,甚至提供給你建議的解決方案。本文章將介紹如何匯出trace以及使用它來優化UI的辦法。

總覽

Systrace可以幫助你分析應用在不同Android系統上的執行情況。它將系統和應用的執行緒執行情況放置在同一條時間線上分析。你首先需要收集系統和應用的trace(後面會告訴你怎麼做),之後Systrace會幫你生成一份細緻、直觀的報告,它展示了裝置在你監測的這段時間內所發生的事情。


圖1. 連續滑動應用5秒的Trace,它並沒有表現得很完美。

圖1展示了應用在滑動不流暢的時候生成的trace。預設縮放成全域性顯示,你可以放大到自己所關注的地方。橫軸代表著時間線,事件記錄按照程序分組,同一個程序內按執行緒進行縱向拆分,每個執行緒記錄自己的工作。

在本例中,一共有三個組:Kernel, SurfaceFlinger, App,他們分別以包名為標識。每個應用程序都會包含其中所有執行緒的記錄訊號,你可以看到從InputEvent到RenderThread都有。

生成Trace

在獲取trace之前需要做一些啟動工作。首先,裝置要求API>=16(Android 4.1),之後通過正常的Debug流程(開啟除錯、連線工作環境、安裝App)連線裝置。由於需要記錄磁碟活動和核心工作,你可能需要root許可權。不過大部分時候你只要能夠正常Debug即可。

Systrace 可以通過命令列或者圖形介面啟動,本篇文章重點介紹通過命令列使用Systrace。

在Android 4.3及以上的系統中獲取trace

在4.3以上的系統獲取Trace步驟:

  1. 保證裝置USB連線正常,並可以debug;
  2. 在命令列中設定選項,開啟trace,比如:
 
1
2
3
    $ cd android-sdk/platform-tools/systrace
    $ python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
 
  1. 在裝置上做任何你想讓trace記錄的操作。

你可以通過Systrace選項來了解更多命令列選項。

在Android 4.2及以下的系統中獲取trace

在4.2及以下的系統中高效地使用Systrace的話,你需要在配置的時候顯式指定要trace的程序種類。一共有這兩類種類:

  • 普通系統程序,比如圖形、聲音、輸入等。(通過tags設定,具體在Systrace命令列中有介紹)
  • 底層系統程序,比如CPU、核心、檔案系統活動。(通過options設定,具體在Systrace命令列中有介紹)

你可以通過以下命令列操作來設定tags:

  1. 使用 --set-tags選項:
 
1
2
3
    $ cd android-sdk/platform-tools/systrace
    $ python systrace.py --set-tags=gfx,view,wm
 
  1. 重啟adb shell來trace這些程序:
 
1
2
3
    $ adb shell stop
    $ adb shell start
 

你也可以通過手機上的圖形介面設定tags:

  1. 在裝置上進入設定> 開發者選項 > 監控 > 啟用跟蹤(部分手機上沒有這個選項);
  2. 選擇追蹤程序型別,點選確認。

注意: 在圖形介面中設定tag時adb shell不用重新啟動。

在配置完tags後,你可以開始收集操作資訊了。

如何在當前設定下啟動trace:

  1. 保證裝置的usb連線正常,並且可以正常debug;
  2. 使用低系統等級的命令列選項開啟trace,比如:
    $ python systrace.py --cpu-freq --cpu-load --time=10 -o mytracefile.html
  3. 在裝置上做任何你想讓trace記錄的操作。

你可以通過Systrace選項來了解更多命令列選項。

分析trace報告

在你獲取trace之後你可以在網頁瀏覽器中開啟它。這部分內容告訴你怎麼通過trace去分析和解決UI效能。

監視幀數

每個應用都有一行專門顯示frame,每一幀就顯示為一個綠色的圓圈。不過也有例外,當顯示為黃色或者紅色的時候,它的渲染時間超過了16.6ms(即達不到60fps的水準)。’w’鍵可以放大,看看這一幀的渲染過程中系統到底做了什麼。

提示:你可以按右上角的’?’按鈕來檢視介面使用幫助。


圖2. Systrace顯示長渲染時間的幀

單擊該幀可以高亮它,這時候跟該幀有關的內容會被突出顯示。在5.0及以上的系統中,顯示工作被拆分成UI執行緒和Render執行緒兩部分;在5.0以下的系統中,所有的顯示工作在UI執行緒中執行。

點選單個Frame下面的元件可以看他們所花費的時間。每個事件(比如performTraversals)都會在你選中的時候顯示出它們呼叫了哪些方法及所用的時間。

調查警告事件

Systrace會自動分析事件,它會將任何它認為效能有問題的東西都高亮警告,並提示你要怎麼去優化。


圖3. 選擇一個被高亮幀,它會顯示出檢測到的問題(回收ListView消耗時間太長)。

在你選擇類似圖三中的問題幀之後,它就會提示你檢測出的問題。在這個例子中,它被警告的主要原因是ListView的回收和重新繫結花費太多時間。在Systrace中也會提供一些對應連結,它們會提供更多解釋。

如果你想知道UI執行緒怎麼會花費這麼多時間的話,你可以使用TraceView,它會告訴你都是哪些函式在消耗時間。

你可以通過右側的’Alert’選項卡來檢視整個trace過程中發生的所有問題,並進行快速定位。


圖4. 點選Alert選項卡。

你可以將Alert面板中的問題視為需要處理的bug,很有可能每一次微小的優化能夠去除整個應用中的警告!

應用級別除錯

Systrace並不會追蹤應用的所有工作,所以你可以在有需求的情況下自己新增要追蹤的程式碼部分。在Android 4.3及以上的程式碼中,你可以通過Trace類來實現這個功能。它能夠讓你在任何時候跟蹤應用的一舉一動。在你獲取trace的過程中,Trace.beginSection()Trace.endSection()之間程式碼工作會一直被追蹤。

下面這部分程式碼展示了使用Trace的例子,在整個方法中含有兩個Trace塊。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void ProcessPeople() {
    Trace.beginSection("ProcessPeople");
    try {
        Trace.beginSection("Processing Jane");
        try {
           // 待追蹤的程式碼
        } finally {
            Trace.endSection(); // 結束 "Processing Jane"
        }
 
        Trace.beginSection("Processing John");
        try {
            // 待追蹤的程式碼
        } finally {
            Trace.endSection(); // 結束 "Processing John"
        }
    } finally {
        Trace.endSection(); // 結束 "ProcessPeople"
    }
}
 

注意:在Trace是被巢狀在另一個Trace中的時候,endSection()方法只會結束理它最近的一個beginSection(String)。即在一個Trace的過程中是無法中斷其他Trace的。所以你要保證endSection()beginSection(String)呼叫次數匹配。

注意:Trace的begin與end必須在同一執行緒之中執行!

當你使用應用級別追蹤的時候,你必須通過-a或者-app=來顯式地指定應用包名。可以通過Systrace指南檢視更多關於它的資訊。

你在評估應用的時候應該開啟應用級別跟蹤,即使當你沒有手動新增Trace訊號。因為很多庫函式裡面是有新增Trace訊號的(比如RecyclerView),它們往往能夠提供很多資訊。