以觸發條件為基礎的剖析

ProfilingManager 支援根據系統觸發條件擷取設定檔。系統會管理記錄程序,並將產生的設定檔提供給應用程式。

觸發條件與效能關鍵事件相關聯。系統記錄的設定檔會提供詳細的偵錯資訊,協助您瞭解與這些觸發條件相關聯的關鍵使用者歷程 (CUJ)。

擷取歷來資料

許多觸發條件都需要分析事件發生前的歷來資料。觸發條件本身通常是問題的結果,而非根本原因。如果等到觸發條件發生後才開始剖析,可能就無法找出根本原因。

舉例來說,在 UI 執行緒上長時間執行的作業會導致應用程式無回應 (ANR) 錯誤。當系統偵測到 ANR 並向應用程式發出信號時,作業可能已經完成。如果此時才開始剖析,就會錯過實際的封鎖工作。

我們無法準確預測某些觸發條件何時發生,因此無法事先手動啟動設定檔。

為什麼要使用觸發條件擷取功能?

使用剖析觸發條件的主要原因,是擷取無法預測事件的資料,因為應用程式無法在這些事件發生前手動開始記錄。剖析觸發條件可用於:

  • 偵錯效能問題:診斷 ANR、記憶體流失和其他穩定性問題。
  • 最佳化關鍵使用者歷程:分析及改善流程,例如應用程式啟動。
  • 瞭解使用者行為:深入分析事件,例如使用者主動退出應用程式。

設定觸發條件

下列程式碼示範如何註冊 TRIGGER_TYPE_APP_FULLY_DRAWN 觸發條件,並對其套用頻率限制。

Kotlin

fun recordWithTrigger() {
    val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java)

    val triggers = ArrayList<ProfilingTrigger>()

    val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN)
        .setRateLimitingPeriodHours(1)

    triggers.add(triggerBuilder.build())

    val mainExecutor: Executor = Executors.newSingleThreadExecutor()

    val resultCallback = Consumer<ProfilingResult> { profilingResult ->
        if (profilingResult.errorCode == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.resultFilePath
            )
            setupProfileUploadWorker(profilingResult.resultFilePath)
        } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode=" + profilingResult.errorCode + " errormsg=" + profilingResult.errorMessage
            )
        }
    }

    profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback)
    profilingManager.addProfilingTriggers(triggers)

}

Java

public void recordWithTrigger() {
  ProfilingManager profilingManager = getApplicationContext().getSystemService(
      ProfilingManager.class);
  List<ProfilingTrigger> triggers = new ArrayList<>();
  ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder(
      ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN);
  triggerBuilder.setRateLimitingPeriodHours(1);
  triggers.add(triggerBuilder.build());

  Executor mainExecutor = Executors.newSingleThreadExecutor();
  Consumer<ProfilingResult> resultCallback =
      new Consumer<ProfilingResult>() {
        @Override
        public void accept(ProfilingResult profilingResult) {
          if (profilingResult.getErrorCode() == ProfilingResult.ERROR_NONE) {
            Log.d(
                "ProfileTest",
                "Received profiling result file=" + profilingResult.getResultFilePath());
            setupProfileUploadWorker(profilingResult.getResultFilePath());
          } else {
            Log.e(
                "ProfileTest",
                "Profiling failed errorcode="
                    + profilingResult.getErrorCode()
                    + " errormsg="
                    + profilingResult.getErrorMessage());
          }
        }
      };
  profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);

}

程式碼會執行下列步驟:

  1. 取得管理工具:擷取 ProfilingManager 服務。
  2. 定義觸發條件:為 TRIGGER_TYPE_APP_FULLY_DRAWN 建構 ProfilingTrigger。當應用程式回報已完成啟動並可互動時,就會發生這個事件。
  3. 設定頻率限制:對這個特定觸發條件 (setRateLimitingPeriodHours(1)) 套用 1 小時的頻率限制,防止應用程式每小時記錄多個啟動設定檔。
  4. 註冊事件監聽器:呼叫 registerForAllProfilingResults,定義處理結果的回呼。這個回呼會透過 getResultFilePath() 接收已儲存設定檔的路徑。
  5. 新增觸發條件:使用 addProfilingTriggers 向 ProfilingManager 註冊觸發條件清單。
  6. Fire event:呼叫 reportFullyDrawn(),將 TRIGGER_TYPE_APP_FULLY_DRAWN 事件發送至系統,觸發設定檔收集,前提是系統背景追蹤正在執行,且有可用的速率限制器配額。這個選用步驟會示範端對端流程,因為應用程式必須為這個觸發條件呼叫 reportFullyDrawn()。

擷取追蹤記錄

系統會將觸發條件式設定檔儲存在與其他設定檔相同的目錄中。觸發追蹤記錄的檔案名稱格式如下:

profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>

您可以使用 ADB 提取檔案。舉例來說,如要使用 ADB 提取以範例程式碼擷取的系統追蹤記錄,程式碼可能如下所示:

adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace

如要進一步瞭解如何以視覺化方式呈現這些追蹤記錄,請參閱「擷取及分析剖析資料」。

背景追蹤的運作方式

為了擷取觸發條件之前的資料,OS 會定期啟動背景追蹤。如果背景追蹤記錄處於啟用狀態,且應用程式已註冊,則觸發事件發生時,系統會將追蹤記錄設定檔儲存至應用程式的目錄。設定檔就會包含觸發前發生的資訊。

設定檔儲存後,系統會使用提供給 registerForAllProfilingResults 的回呼通知應用程式。這個回呼會提供擷取設定檔的路徑,您可以呼叫 ProfilingResult#getResultFilePath() 來存取。

這張圖表說明背景追蹤快照的運作方式,其中環狀緩衝區會在觸發事件前擷取資料。
圖 1:背景追蹤記錄快照的運作方式。

為減少對裝置效能和電池續航力的影響,系統不會持續執行背景追蹤。而是採用取樣方法。系統會在設定的時間範圍內 (有最短和最長持續時間),隨機啟動背景追蹤。隨機間隔這些追蹤記錄可提高觸發條件涵蓋率。

系統觸發的設定檔有系統定義的大小上限,因此會使用環狀緩衝區。緩衝區滿了之後,新的追蹤記錄資料會覆寫最舊的資料。如圖 1 所示,如果緩衝區已滿,擷取的追蹤記錄可能不會涵蓋背景錄製的整個時間長度,而是代表觸發前最近的活動。

實施觸發條件專屬的頻率限制

高頻率觸發條件可能會快速消耗應用程式的頻率限制器配額。如要進一步瞭解頻率限制器,建議您參閱「頻率限制器的運作方式」。為避免單一觸發條件類型耗盡配額,您可以實施觸發條件專屬的頻率限制。

ProfilingManager 支援應用程式定義的觸發條件專屬頻率限制。除了現有的頻率限制器外,您還可以新增另一層時間限制。使用 setRateLimitingPeriodHours API 設定觸發條件的特定冷卻時間。冷卻時間結束後,即可再次觸發。

在本機偵錯觸發條件

由於背景追蹤會在隨機時間執行,因此在本機偵錯觸發條件相當困難。如要強制執行背景追蹤記錄進行測試,請使用下列 ADB 指令:

adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>

這個指令會強制系統針對指定套件啟動連續背景追蹤,讓每個觸發條件都能在頻率限制器允許的情況下收集設定檔。

您也可以啟用其他偵錯選項,例如在本機偵錯時停用頻率限制器。詳情請參閱「本機剖析的偵錯指令」。