以觸發條件為基礎的剖析

在 Android 16 (API 級別 36) 以上版本中,ProfilingManager 可讓您自動擷取設定檔,以回應系統觸發條件,例如應用程式無回應 (ANR) 錯誤、記憶體不足 (OutOfMemoryError) 異常終止或應用程式啟動事件。由於您無法預測這些事件何時會在現場發生,因此無法事先手動開始錄製。使用觸發條件式剖析時,系統會管理擷取作業,並將產生的設定檔傳送至應用程式,以便您:

  • 對穩定性問題進行偵錯:診斷無法預測的 ANR 和記憶體流失問題。
  • 最佳化關鍵使用者歷程 (CUJ):分析應用程式啟動等流程 (TRIGGER_TYPE_COLD_START 和 TRIGGER_TYPE_APP_FULLY_DRAWN)。
  • 瞭解使用者行為:檢查使用者主動退出應用程式等事件。

如需可用觸發條件的完整清單,請參閱 ProfilingTrigger。

觸發條件類型

觸發條件的差異在於,系統在事件發生時擷取設定檔的方式。

使用背景追蹤記錄的觸發條件

許多觸發條件 (例如 ANR) 都是先前問題造成的結果。如果等到系統偵測到 ANR 後才開始追蹤,就會錯過導致 ANR 的封鎖工作。為了擷取事件發生前的活動,下列觸發條件會儲存系統有效背景追蹤的快照。如果事件發生時沒有背景追蹤記錄在執行,系統就不會收集設定檔:

開始新擷取的觸發條件

下列觸發條件不依賴背景追蹤。而是在事件發生時,系統會啟動新的設定檔擷取:

擷取行為因異常狀況而異的觸發條件

對於下列異常偵測觸發條件,擷取的設定檔類型 (儲存有效背景追蹤記錄的快照,或開始新的擷取作業) 和頻率限制行為,取決於系統偵測到的特定異常狀況:

設定觸發條件

下列程式碼示範如何註冊 TRIGGER_TYPE_APP_FULLY_DRAWN 觸發條件,並設定等待期。

Kotlin

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun recordWithTrigger() {
    val profilingManager =
        applicationContext.getSystemService(ProfilingManager::class.java) ?: return

    val triggers = ArrayList<ProfilingTrigger>()

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

    triggers.add(triggerBuilder.build())

    val callbackExecutor: 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(callbackExecutor, resultCallback)
    profilingManager.addProfilingTriggers(triggers)

    Choreographer.getInstance().postFrameCallback { frameTimeNanos ->
        // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted.
        reportFullyDrawn()
    }
}

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 callbackExecutor = 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(callbackExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);

  Choreographer.getInstance().postFrameCallback((f) -> {
    // This will cause the TRIGGER_TYPE_APP_FULLY_DRAWN to be emitted.
    reportFullyDrawn();
  });
}

程式碼會執行下列步驟:

  1. 取得管理工具:擷取 ProfilingManager 服務。
  2. 定義觸發條件:為 TRIGGER_TYPE_APP_FULLY_DRAWN 建構 ProfilingTrigger。當應用程式在活動啟動的冷啟動期間呼叫 reportFullyDrawn(),回報已完成啟動並可互動時,就會發生此事件。
  3. 設定觸發條件等待期:除了系統頻率限制器外,使用 setRateLimitingPeriodHours 為這個特定觸發條件套用 1 小時的等待期。這項冷卻機制可避免應用程式每小時記錄多個啟動設定檔。
  4. 註冊事件監聽器:呼叫 registerForAllProfilingResults,定義處理結果的回呼。這個回呼會透過 getResultFilePath() 接收已儲存設定檔的路徑。
  5. 新增觸發條件:使用 addProfilingTriggers 向 ProfilingManager 註冊觸發條件清單。
  6. Fire event:發布 Choreographer 影格回呼,在繪製下一個影格時呼叫 reportFullyDrawn(),進而向系統發出 TRIGGER_TYPE_APP_FULLY_DRAWN 事件,並在系統背景追蹤執行中且頻率限制器配額可用時,觸發設定檔收集。如要觸發這項事件,請確認應用程式會呼叫 reportFullyDrawn()。

觸發條件生命週期

應用程式和系統重新啟動後,已註冊的觸發條件仍會保留。您不必在每次應用程式啟動或系統重新啟動後重新註冊觸發條件。使用 addProfilingTriggers 註冊觸發條件後,系統會自動為應用程式維護這些觸發條件,直到您移除這些觸發條件或解除安裝應用程式為止。

取消註冊觸發條件的時機

由於已註冊的觸發條件在應用程式重新啟動和系統重新啟動後仍會保留,因此在後續啟動時略過 addProfilingTriggers,並不會停止在先前工作階段中註冊的觸發條件。如要停止擷取特定事件或所有事件的設定檔,請明確呼叫 removeProfilingTriggersByType 或 clearProfilingTriggers。

在下列情況下取消註冊觸發條件:

  • 指定同類群組或復原遠端旗標:您可以使用遠端設定或 A/B 測試旗標,跨同類群組進行區隔剖析。每當裝置離開取樣同類群組或旗標關閉時,請取消註冊觸發條件。
  • 完成偵錯活動:收集到足夠的設定檔來診斷問題或發布修正程式後,請移除觸發條件。取消註冊不必要的觸發條件,可保留裝置儲存空間和應用程式的頻率限制器配額,供其他剖析要求使用。

回呼生命週期

與直接剖析要求不同,觸發條件式剖析只會將結果傳送至向 registerForAllProfilingResults 註冊的全域事件監聽器。在回呼中,呼叫 ProfilingResult.getTriggerType 找出啟動擷取的觸發條件,並呼叫 ProfilingResult.getResultFilePath 找出儲存的設定檔。如要進一步瞭解觸發設定檔檔案名稱、使用 adb 提取檔案,以及在背景上傳結果,請參閱「擷取及上傳設定檔」。

雖然觸發條件在應用程式和系統重新啟動後仍會保留,但結果回呼不會保留。應用程式啟動完成後,在背景 Executor 上註冊回呼 (這樣就不會減慢冷啟動速度),以便在下列兩種情況下接收設定檔:

  • 應用程式執行時:如果觸發條件不會停止或導致應用程式停止運作,系統會在觸發條件發生且設定檔儲存時,在提供的 Executor 上叫用回呼。
  • 應用程式終止後:如果觸發條件通常涉及或發生在應用程式終止之前 (例如 TRIGGER_TYPE_ANR、TRIGGER_TYPE_OOM 或 TRIGGER_TYPE_KILL_RECENTS),或者應用程式在擷取完成前停止,系統會在背景儲存設定檔,並在應用程式重新啟動和系統重新啟動時將結果排入佇列。系統最多會保留未傳送的佇列結果 7 天,並在應用程式下次執行並呼叫 registerForAllProfilingResults 時傳送。

背景追蹤的運作方式

為了平衡分析負擔和擷取實用構件,系統不會持續執行背景追蹤。而是會以隨機間隔啟動背景追蹤,定期取樣。

系統觸發的背景追蹤記錄會使用環狀緩衝區,其大小上限由系統定義。緩衝區填滿時,新的追蹤記錄資料會覆寫最舊的資料。如圖 1 所示,當註冊的觸發條件在背景追蹤記錄處於啟用狀態,且頻率限制器配額可用時觸發,系統會儲存環狀緩衝區快照,其中包含觸發條件之前的最新活動。

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

設定觸發條件專屬的冷卻時間

高頻率觸發條件可能會快速消耗應用程式的頻率限制器配額。為避免單一觸發條件類型耗盡配額,請使用 setRateLimitingPeriodHours,在系統頻率限制器上,為每個觸發條件新增最短等待期。

在本機偵錯觸發條件

由於背景追蹤在正式環境中會隨機執行,因此在本機測試觸發條件時,必須強制執行連續背景追蹤,並略過套件的系統層級頻率限制器 (使用 setRateLimitingPeriodHours 設定的每個觸發條件冷卻時間仍適用,而 rate_limiter.disabled 僅適用於應用程式驅動的 requestProfiling 呼叫)。

如需 adb 指令來強制執行背景追蹤、從指令列模擬觸發條件,以及檢查服務狀態,請參閱「本機剖析偵錯指令」中的「強制啟用背景追蹤,以便測試觸發條件」。