アプリ主導のプロファイルとトリガーベースのプロファイルのどちらをキャプチャする場合でも、ProfilingManager は完成したファイルをデバイスに保存し、登録済みのコールバックに ProfilingResult を配信します。ProfilingResult.getResultFilePath を呼び出して、保存されたプロファイルのパスを取得します。
- ローカルテスト中:
adbを使用してファイルをパソコンに pull します。 - 本番環境: プロファイルを圧縮してサーバーにアップロードする
WorkManagerジョブにパスを渡します。
デバイスからプロファイルを取得する
このセクションでは、ProfilingManager がデバイス上のプロファイルを保存する場所、自動ファイル クリーンアップの仕組み、adb を使用してファイルをローカルに pull する方法について説明します。
ファイルの場所と命名形式
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>は、setTagで構成された、またはrequestProfilingに渡された、呼び出し元が指定したタグの最初の 20 文字の英数字(およびハイフン)です。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: システム トレース- Java ヒープダンプの場合は
.perfetto-java-heap-dump .perfetto-heap-profile(ヒープ プロファイルの場合).perfetto-stack-sample: スタック サンプリング プロファイル
オンデバイスのストレージとクリーンアップ
デバイスのストレージをすぐに解放するには、アップロードが成功した直後に、アップロード ワーカー内の各プロファイル ファイルを削除します(自動クリーンアップは、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を拡張するTraceUploadWorkerクラスを作成します。doWorkを実装して、プロファイル ファイルがまだ存在することを確認し、バックエンド SDK または HTTP クライアントを使用して圧縮してアップロードし、アップロードが成功したらローカル ファイルを削除します。 - 作業のスケジュールを設定する:
- ワーカーの
OneTimeWorkRequestを作成します。 - 制約を設定する:
setRequiredNetworkType(NetworkType.UNMETERED)、setRequiresDeviceIdle(true)、setRequiresCharging(true)を使用して、デバイスが Wi-Fi に接続され、充電中で、アイドル状態のときにのみアップロードが実行されるようにします。 - データを渡す:
setInputDataを使用して、getResultFilePathからワーカーにプロファイル パスを渡します。 - エンキュー:
WorkManager.enqueueを呼び出して、リクエストをWorkManagerに送信します。
- ワーカーの
次のステップ
プロファイルを取得またはアップロードしたら、Perfetto UI で可視化したり、PerfettoSQL で個々のプロファイルをクエリしたり、トレースを一括分析したり、AI でプロファイルを分析したりできます。スケーラブルなサーバーサイド分析パイプラインの設定方法については、Kubernetes への Bigtrace のデプロイをご覧ください。