Независимо от того, какой профиль вы создаете, управляемый приложением или на основе триггера, ProfilingManager сохраняет готовый файл на устройстве и отправляет ProfilingResult на зарегистрированный обратный вызов. Вызовите ProfilingResult.getResultFilePath, чтобы получить путь к сохраненному профилю:
- При локальном тестировании. Перенесите файл на компьютер с помощью
adb. - В рабочей среде. Передайте путь к заданию
WorkManager, которое сжимает и загружает профиль на ваш сервер.
Как получить профили с устройства
В этом разделе описано, где 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 в приложении (включен в последние версии модуляProfiling).<profile-type-ext>– расширение имени файла для типа профиля:.perfetto-traceдля трассировки системы.perfetto-java-heap-dumpдля дампов кучи Java.perfetto-heap-profileдля профилей кучи.perfetto-stack-sampleдля профилей выборки стека
Хранилище устройства и очистка
Чтобы быстро освободить хранилище устройства, удаляйте каждый файл профиля в рабочем процессе загрузки сразу после успешной загрузки. Автоматическая очистка запускается, только когда ProfilingManager передает результаты вашему приложению. Если приложение перестанет регистрировать обратные вызовы после завершения кампании, незагруженные файлы могут остаться на диске. В качестве резервного варианта в последних версиях модуля Profiling библиотека ProfilingManager также автоматически удаляет доставленные файлы в каталоге хранилища, предназначенном для приложения, если они старше пяти дней, когда доставляются новые результаты.
Загрузка профилей в рабочую версию с помощью WorkManager
Поскольку размер файлов профиля может составлять несколько мегабайт, запланируйте загрузку в фоновом режиме, когда устройство подключено к безлимитной сети (Wi-Fi), заряжается и не используется.
Перед загрузкой сжимайте файл профиля (например, с помощью GZIPOutputStream или ZipOutputStream). Профили Perfetto protobuf и дампы кучи Java значительно сжимаются, что снижает требования к пропускной способности сети и затраты на хранение данных.
Добавление зависимостей WorkManager
ProfilingManager не зависит от облака, поэтому вы можете запланировать загрузку профилей в любой бэкенд с помощью WorkManager. Добавьте библиотеку WorkManager в файл build.gradle.kts:
Kotlin
dependencies { implementation("androidx.work:work-runtime:2.12.0") }
Яркий
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()); }
Анализ кода
В приведенном выше примере выполняются следующие действия:
- Определите воркер. Создайте класс
TraceUploadWorker, расширяющийWorker. РеализуйтеdoWork, чтобы убедиться, что файл профиля все ещё существует, сжать и загрузить его с помощью SDK серверной части или HTTP-клиента, а затем удалить локальный файл после успешной загрузки. - Составьте расписание.
- Создайте
OneTimeWorkRequestдля сотрудника. - Задайте ограничения. Используйте
setRequiredNetworkType(NetworkType.UNMETERED),setRequiresDeviceIdle(true)иsetRequiresCharging(true), чтобы загрузка выполнялась, только когда устройство подключено к Wi-Fi, заряжается и не используется. - Передача данных. Используйте
setInputData, чтобы передать путь к профилю изgetResultFilePathв рабочий процесс. - Постановка в очередь. Отправьте запрос в
WorkManager, вызвав методWorkManager.enqueue.
- Создайте
Дальнейшие действия
После получения или загрузки профилей визуализируйте их в Perfetto UI, запросите отдельные профили с помощью PerfettoSQL, проанализируйте трассировки в массовом порядке или проанализируйте профили с помощью ИИ. Инструкции по настройке масштабируемого конвейера анализа на стороне сервера можно найти в статье Развертывание Bigtrace в Kubernetes.