以觸發條件為基礎的剖析

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. 新增觸發條件:使用 addProfilingTriggersProfilingManager 註冊觸發條件清單。
  6. 觸發事件:呼叫 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
的暫時目錄中提取設定檔。

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

背景追蹤功能的運作方式

如要擷取觸發事件發生前的資料,作業系統會定期啟動背景追蹤。如果觸發條件在背景追蹤記錄處於啟用狀態時發生,且應用程式已註冊該觸發條件,系統就會將追蹤記錄設定檔儲存至應用程式的目錄。然後,設定檔會包含導致觸發事件的資訊。

設定檔儲存完畢後,系統會使用提供給 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>

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

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