Pembuatan profil berbasis pemicu

Di Android 16 (API level 36) dan yang lebih tinggi, ProfilingManager memungkinkan Anda mengambil profil secara otomatis sebagai respons terhadap pemicu sistem, seperti error Aplikasi Tidak Merespons (ANR), error Kehabisan Memori (OutOfMemoryError), atau peristiwa startup aplikasi. Karena Anda tidak dapat memprediksi kapan banyak peristiwa ini akan terjadi di lapangan, memulai perekaman secara manual terlebih dahulu tidaklah praktis. Dengan profiling berbasis pemicu, sistem akan mengelola perekaman dan mengirimkan profil yang dihasilkan ke aplikasi Anda sehingga Anda dapat:

  • Men-debug masalah stabilitas: Mendiagnosis ANR dan kebocoran memori yang tidak dapat diprediksi.
  • Mengoptimalkan perjalanan penting pengguna (CUJ): Analisis alur seperti startup aplikasi (TRIGGER_TYPE_COLD_START dan TRIGGER_TYPE_APP_FULLY_DRAWN).
  • Memahami perilaku pengguna: Periksa peristiwa seperti keluar dari aplikasi yang dimulai oleh pengguna.

Untuk mengetahui daftar lengkap pemicu yang tersedia, lihat ProfilingTrigger.

Jenis pemicu

Pemicu berbeda dalam cara sistem menangkap profil saat peristiwa terjadi.

Pemicu yang menggunakan trace latar belakang

Banyak pemicu—seperti ANR—merupakan konsekuensi dari masalah sebelumnya. Memulai trace hanya setelah sistem mendeteksi ANR akan melewatkan pekerjaan pemblokiran yang menyebabkan ANR. Untuk merekam aktivitas yang mengarah ke peristiwa, pemicu berikut menyimpan snapshot trace latar belakang aktif sistem. Jika tidak ada pelacakan latar belakang yang berjalan saat peristiwa terjadi, tidak ada profil yang dikumpulkan:

Pemicu yang memulai pengambilan baru

Pemicu berikut tidak bergantung pada pelacakan latar belakang. Sebagai gantinya, sistem akan memulai pengambilan profil baru saat peristiwa terjadi:

Pemicu yang perilaku perekamannya bervariasi menurut anomali

Untuk pemicu anomali berikut, jenis profil yang diambil (menyimpan snapshot rekaman aktivitas latar belakang yang aktif atau memulai pengambilan baru) dan perilaku pembatasan kapasitas bergantung pada anomali spesifik yang dideteksi oleh sistem:

Menyiapkan pemicu

Kode berikut menunjukkan cara mendaftar untuk pemicu TRIGGER_TYPE_APP_FULLY_DRAWN dan menetapkan periode tunggu untuk pemicu tersebut.

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();
  });
}

Kode ini melakukan langkah-langkah berikut:

  1. Mendapatkan pengelola: Mengambil layanan ProfilingManager.
  2. Menentukan pemicu: Mem-build ProfilingTrigger untuk TRIGGER_TYPE_APP_FULLY_DRAWN. Peristiwa ini terjadi saat aplikasi memanggil reportFullyDrawn() selama cold start yang dimulai aktivitas untuk melaporkan bahwa aplikasi telah selesai memulai dan bersifat interaktif.
  3. Menetapkan periode tunggu pemicu: Menerapkan periode tunggu 1 jam ke pemicu khusus ini menggunakan setRateLimitingPeriodHours selain pembatas kapasitas sistem. Periode tunggu ini mencegah aplikasi merekam lebih dari satu profil startup per jam.
  4. Daftarkan pemroses: Memanggil registerForAllProfilingResults untuk menentukan callback yang menangani hasil. Callback ini menerima jalur profil yang disimpan melalui getResultFilePath().
  5. Menambahkan pemicu: Mendaftarkan daftar pemicu ke ProfilingManager menggunakan addProfilingTriggers.
  6. Peristiwa pengaktifan: Memposting callback frame Choreographer yang memanggil reportFullyDrawn() setelah frame berikutnya digambar, yang memunculkan peristiwa TRIGGER_TYPE_APP_FULLY_DRAWN ke sistem, sehingga memicu pengumpulan profil dengan asumsi pelacakan latar belakang sistem sedang berjalan dan kuota pembatas kapasitas tersedia. Agar pemicu ini terjadi, pastikan aplikasi Anda memanggil reportFullyDrawn().

Siklus proses pemicu

Pemicu yang terdaftar akan tetap ada setiap kali aplikasi dimulai ulang dan sistem di-reboot. Anda tidak perlu mendaftarkan ulang pemicu setiap kali aplikasi dimulai atau setelah sistem dimulai ulang—setelah Anda mendaftarkan pemicu menggunakan addProfilingTriggers, sistem akan mempertahankannya secara otomatis untuk aplikasi Anda hingga Anda menghapusnya atau aplikasi di-uninstal.

Kapan harus membatalkan pendaftaran pemicu

Karena pemicu yang terdaftar tetap ada saat aplikasi dimulai ulang dan sistem dimulai ulang, melewati addProfilingTriggers pada peluncuran berikutnya tidak akan menghentikan pemicu yang terdaftar di sesi sebelumnya. Untuk berhenti merekam profil untuk peristiwa tertentu atau untuk semua peristiwa, panggil removeProfilingTriggersByType atau clearProfilingTriggers secara eksplisit.

Batalkan pendaftaran pemicu dalam situasi berikut:

  • Menargetkan kelompok atau me-roll back flag jarak jauh: Anda dapat melakukan segmentasi profil di seluruh kelompok menggunakan konfigurasi jarak jauh atau flag pengujian A/B. Setiap kali perangkat keluar dari kelompok sampel atau tanda dinonaktifkan, batalkan pendaftaran pemicu.
  • Menyelesaikan kampanye proses debug: Setelah Anda mengumpulkan cukup profil untuk mendiagnosis masalah atau mengirimkan perbaikan, hapus pemicu. Membatalkan pendaftaran pemicu yang tidak diperlukan akan menghemat penyimpanan perangkat dan kuota pembatas kapasitas aplikasi Anda untuk permintaan pembuatan profil lainnya.

Siklus proses callback

Tidak seperti permintaan pembuatan profil langsung, profil berbasis pemicu hanya memberikan hasil ke pemroses global yang terdaftar di registerForAllProfilingResults. Dalam callback, panggil ProfilingResult.getTriggerType untuk mengidentifikasi pemicu yang memulai pengambilan, dan panggil ProfilingResult.getResultFilePath untuk menemukan file profil yang disimpan. Untuk mengetahui detail tentang nama file profil pemicu, mengambil file dengan adb, dan mengupload hasil di latar belakang, lihat Mengambil dan mengupload profil.

Meskipun pemicu tetap ada saat aplikasi dimulai ulang dan sistem dimulai ulang, callback hasil Anda tidak akan tetap ada. Daftarkan callback Anda di Executor latar belakang setelah startup aplikasi selesai (agar Anda tidak memperlambat cold start) untuk menerima profil dalam kedua skenario berikut:

  • Saat aplikasi Anda berjalan: Untuk pemicu yang tidak menghentikan atau membuat aplikasi Anda error, sistem akan memanggil callback Anda pada Executor yang disediakan saat pemicu terjadi dan profil disimpan.
  • Setelah penghentian aplikasi: Untuk pemicu yang sering melibatkan atau mendahului penghentian aplikasi (seperti TRIGGER_TYPE_ANR, TRIGGER_TYPE_OOM, atau TRIGGER_TYPE_KILL_RECENTS), atau jika aplikasi Anda berhenti sebelum pengambilan selesai, sistem akan menyimpan profil di latar belakang dan mengantrekan hasilnya di seluruh proses mulai ulang aplikasi dan mulai ulang sistem. Sistem akan mempertahankan hasil antrean yang tidak terkirim hingga 7 hari dan mengirimkannya saat aplikasi Anda berjalan dan memanggil registerForAllProfilingResults di lain waktu.

Cara kerja pelacakan latar belakang

Untuk menyeimbangkan overhead pembuatan profil dengan pengambilan artefak yang berguna, sistem tidak menjalankan pelacakan latar belakang secara terus-menerus. Sebagai gantinya, alat ini mengambil sampel secara berkala dengan memulai pelacakan latar belakang pada interval acak.

Rekaman aktivitas latar belakang yang dipicu sistem menggunakan ring buffer dengan ukuran maksimum yang ditentukan sistem. Saat buffer terisi, data rekaman aktivitas baru akan menimpa data terlama. Seperti yang ditunjukkan pada Gambar 1, saat pemicu terdaftar diaktifkan saat pelacakan latar belakang aktif dan kuota pembatas kapasitas tersedia, sistem akan menyimpan ringkasan ring buffer yang berisi aktivitas terbaru yang mengarah ke pemicu.

Diagram yang menunjukkan cara kerja snapshot rekaman aktivitas latar belakang, dengan buffering cincin yang merekam data sebelum peristiwa pemicu.
Gambar 1. Cara kerja snapshot trace latar belakang.

Menetapkan jeda khusus pemicu

Pemicu frekuensi tinggi dapat dengan cepat menghabiskan kuota pembatas kapasitas aplikasi Anda. Untuk mencegah satu jenis pemicu menghabiskan kuota Anda, gunakan setRateLimitingPeriodHours untuk menambahkan periode tunggu minimum per pemicu di atas pembatas kapasitas sistem.

Men-debug pemicu secara lokal

Karena pelacakan latar belakang berjalan pada interval acak dalam produksi, pengujian pemicu secara lokal memerlukan pemaksaan pelacakan latar belakang berkelanjutan dan mengabaikan pembatas kapasitas tingkat sistem untuk paket Anda (setiap cooldown per pemicu yang ditetapkan dengan setRateLimitingPeriodHours masih berlaku, dan rate_limiter.disabled hanya berlaku untuk panggilan requestProfiling yang didorong aplikasi).

Untuk perintah adb guna memaksa pelacakan latar belakang, menyimulasikan pemicu dari command line, dan memeriksa status layanan, lihat Memaksa pengaktifan pelacakan latar belakang untuk pengujian pemicu di Perintah debug untuk pembuatan profil lokal.