ProfilingManager saves traces locally on the device. While you can retrieve these files using ADB for local debugging, collecting field data requires uploading them to a server.
Trace files can be large (often several MBs). To avoid negatively affecting the user experience or consuming mobile data, you should schedule uploads to occur in the background, preferably when the device is on an unmetered network (Wi-Fi), charging and idle.
Set up a WorkManager upload job
ProfilingManager is cloud-agnostic; you can upload traces to any
infrastructure you choose. The following example demonstrates how to use
WorkManager to schedule an upload job that avoids user disruption.
Code example to setup an upload job
Here's an example on how you can set up a job that is not disruptive to the user to upload traces to your server.
Add WorkManager dependencies
Besides your existing ProfilingManager dependencies, add these Jetpack
libraries to your build.gradle.kts file. WorkManager needs them.
Kotlin
dependencies { implementation("androidx.work:work-runtime:2.11.0") }
Groovy
dependencies { implementation 'androidx.work:work-runtime:2.11.0' }
Code snippet
This code shows how to set up a job for uploading traces. The job should be
setup when the ProfilingResult is received by your app. The profiling section
is omitted in this section but an example can be found in Record a system
trace.
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) .build(); workRequestBuilder.setConstraints(constraints); Data.Builder inputDataBuilder = new Data.Builder(); inputDataBuilder.putString("PROFILE_PATH", profileFilepath); workRequestBuilder.setInputData(inputDataBuilder.build()); workMgr.enqueue(workRequestBuilder.build()); }
Code walkthrough
The code does the following:
Define the worker: Create a
TraceUploadWorkerclass extendingWorker. Implement thedoWork()method to handle the actual file upload logic using your preferred backend SDK or HTTP client.Request profiling: Use
SystemTraceRequestBuilderto configure the trace (duration, buffer policy) andProfiling.requestProfilingto start it.Schedule the work:
Create a
OneTimeWorkRequestfor your worker.Set constraints: Use
setRequiredNetworkType(NetworkType.UNMETERED),setRequiresDeviceIdle(true)andsetRequiresCharging(true)to ensure the upload only happens when the user is on Wi-Fi, charging and not actively using the device. This is important to avoid disruption to the user with the upload job.Pass data: Use
setInputDatato pass the trace path to the worker.Enqueue: Submit the request to WorkManager by calling
WorkManager#enqueue.
Next Steps
After uploading traces, you can analyze them individually or perform bulk trace analysis. For guidance on setting up a scalable analysis pipeline, refer to Deploying Bigtrace on Kubernetes.