擷取及上傳設定檔

無論您擷取的是應用程式驅動的設定檔,還是觸發條件式設定檔,ProfilingManager 都會將完成的檔案儲存在裝置上,並將 ProfilingResult 傳送至已註冊的回呼。呼叫 ProfilingResult.getResultFilePath 即可取得已儲存設定檔的路徑:

擷取裝置上的設定檔

本節說明 ProfilingManager 在裝置上儲存設定檔的位置、自動檔案清理的運作方式,以及如何使用 adb 在本機提取檔案。

檔案位置和命名格式

ProfilingManager 會將經過遮蓋的設定檔儲存在/data/user/0/<app>/files/profiling/的應用程式專屬儲存空間目錄中。檔案名稱格式取決於設定檔的擷取方式:

  • 應用程式導向設定檔:

    profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>
    

    如果在要求設定檔時未提供標記,則會省略 <tag>_:profile_<datetime>_uid-<uid>.<profile-type-ext>。

  • 觸發條件式設定檔:

    profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
    

其中:

  • <app> 是應用程式的套件名稱。
  • <tag> 是呼叫端提供的標記,最多可包含前 20 個英數字元 (和連字號),並使用 setTag 設定或傳遞至 requestProfiling,轉換為小寫,並移除 a-z、0-9 和 - 以外的所有字元。
  • <trigger_type> 是 ProfilingTrigger 中觸發條件的整數常數代碼。請一律在程式碼中呼叫 ProfilingResult.getTriggerType,而非剖析檔案名稱。
  • <datetime> 是記錄設定檔的日期和時間 (yyyy-MM-dd-HH-mm-ss-SSS)。
  • <uid> 是應用程式的 Linux 使用者 ID (包含在最近的 Profiling 模組版本中)。
  • <profile-type-ext> 是擷取設定檔類型的副檔名:
    • .perfetto-trace:系統追蹤記錄
    • .perfetto-java-heap-dump Java 記憶體快照資料
    • .perfetto-heap-profile:堆積快照
    • .perfetto-stack-sample (針對堆疊取樣設定檔)

裝置端儲存空間和清理

如要立即釋出裝置儲存空間,請在上傳成功後,立即刪除上傳 worker 中的每個設定檔 (因為只有在 ProfilingManager 將結果傳送至應用程式時,系統才會執行自動清理作業,否則如果應用程式在廣告活動結束後停止註冊回呼,未上傳的檔案可能會保留在磁碟上)。做為近期 Profiling 模組版本的備用方案,ProfilingManager 也會在傳送新結果時,自動刪除應用程式專屬儲存目錄中超過 5 天的傳送檔案。

使用 WorkManager 在實際工作環境中上傳設定檔

由於設定檔的大小可能達到數 MB,因此請在裝置連上非計量付費網路 (Wi-Fi)、充電和閒置時,排定在背景上傳正式版。

上傳前,請壓縮設定檔 (例如使用 GZIPOutputStream 或 ZipOutputStream)。Perfetto protobuf 設定檔和 Java 記憶體快照資料會大幅壓縮,減少網路頻寬和後端儲存空間費用。

新增 WorkManager 依附元件

ProfilingManager 與雲端無關,因此您可以使用 WorkManager 排定將設定檔上傳至任何後端。將 WorkManager 程式庫新增至 build.gradle.kts 檔案:

Kotlin

   dependencies {
       implementation("androidx.work:work-runtime:2.12.0")
   }
   

Groovy

   dependencies {
       implementation 'androidx.work:work-runtime:2.12.0'
   }
   

排定上傳工作

應用程式收到 ProfilingResult 時,請排定上傳工作。以下範例省略初始剖析要求;如需完整要求範例,請參閱「記錄系統追蹤」。

Kotlin

class TraceUploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        // Perform your uploading work here
        Log.d("ProfileTest", "Uploading trace: " + inputData.getString("PROFILE_PATH"))

        return Result.success()
    }
}

fun setupProfileUploadWorker(profileFilepath: String?) {
    val workMgr = WorkManager.getInstance(applicationContext)
    val workRequestBuilder = OneTimeWorkRequest.Builder(TraceUploadWorker::class)

    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresDeviceIdle(true)
        .setRequiresCharging(true)
        .build()
    workRequestBuilder.setConstraints(constraints)

    val inputDataBuilder = Data.Builder()
    inputDataBuilder.putString("PROFILE_PATH", profileFilepath)
    workRequestBuilder.setInputData(inputDataBuilder.build())

    workMgr.enqueue(workRequestBuilder.build())
}

Java

public static class TraceUploadWorker extends Worker {

  public TraceUploadWorker(
      @androidx.annotation.NonNull Context context,
      @androidx.annotation.NonNull WorkerParameters workerParams) {
    super(context, workerParams);
  }

  @androidx.annotation.NonNull
  @Override
  public Result doWork() {
    // Perform your uploading work here
    Log.d("ProfileTest", "Uploading trace: " + getInputData().getString("PROFILE_PATH"));

    return Result.success();
  }
}

public void setupProfileUploadWorker(String profileFilepath) {
  WorkManager workMgr = WorkManager.getInstance(getApplicationContext());
  OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(
      TraceUploadWorker.class);

  Constraints constraints = new Constraints.Builder()
      .setRequiredNetworkType(NetworkType.UNMETERED)
      .setRequiresDeviceIdle(true)
      .setRequiresCharging(true)
      .build();
  workRequestBuilder.setConstraints(constraints);

  Data.Builder inputDataBuilder = new Data.Builder();
  inputDataBuilder.putString("PROFILE_PATH", profileFilepath);
  workRequestBuilder.setInputData(inputDataBuilder.build());

  workMgr.enqueue(workRequestBuilder.build());
}

程式碼逐步操作說明

上述範例會執行下列步驟:

  • 定義 worker:建立擴充 Worker 的 TraceUploadWorker 類別。實作 doWork,確認設定檔仍存在,使用後端 SDK 或 HTTP 用戶端壓縮並上傳設定檔,並在上傳成功後刪除本機檔案。
  • 安排工作:
    • 為 worker 建立 OneTimeWorkRequest。
    • 設定限制:使用 setRequiredNetworkType(NetworkType.UNMETERED)、setRequiresDeviceIdle(true) 和 setRequiresCharging(true),讓上傳作業只在裝置連上 Wi-Fi、充電和閒置時執行。
    • 傳遞資料:使用 setInputData 將設定檔路徑從 getResultFilePath 傳遞至 worker。
    • Enqueue:呼叫 WorkManager.enqueue,將要求提交至 WorkManager。

後續步驟

擷取或上傳設定檔後,您可以在 Perfetto UI 中以視覺化方式呈現、使用 PerfettoSQL 查詢個別設定檔、大量分析追蹤記錄,或使用 AI 分析設定檔。如需設定可擴充伺服器端分析管道的指南,請參閱「在 Kubernetes 上部署 Bigtrace」。