Tetikleyici tabanlı profil oluşturma

ProfilingManager, sistem tetikleyicilerine dayalı profil yakalamayı destekler. Sistem, kayıt işlemini yönetir ve elde edilen profili uygulamanıza sağlar.

Tetikleyiciler, performans açısından kritik etkinliklere bağlıdır. Sistem tarafından kaydedilen profiller, bu tetikleyicilerle ilişkili kritik kullanıcı yolculukları (CUJ'ler) için ayrıntılı hata ayıklama bilgileri sağlar.

Geçmiş verileri yakalama

Birçok tetikleyici, etkinliğe yol açan geçmiş verilerin analiz edilmesini gerektirir. Tetikleyici genellikle asıl neden değil, bir sorunun sonucudur. Yalnızca tetikleyici gerçekleştikten sonra profil oluşturmaya başlarsanız temel neden çoktan kaybolmuş olabilir.

Örneğin, kullanıcı arayüzü iş parçacığında uzun süreli bir işlem, Uygulama Yanıt Vermiyor (ANR) hatasına neden olur. Sistem ANR'yi algılayıp uygulamaya sinyal gönderene kadar işlem tamamlanmış olabilir. Bu durumda, profil oluşturma işlemi başlatıldığında asıl engelleme işlemi kaçırılır.

Bazı tetikleyicilerin tam olarak ne zaman gerçekleşeceğini tahmin etmek mümkün olmadığından, bir profili önceden manuel olarak başlatmak imkansızdır.

Tetikleyici tabanlı yakalama özelliğini neden kullanmalısınız?

Profil oluşturma tetikleyicilerini kullanmanın temel nedeni, bir uygulamanın bu olaylar gerçekleşmeden önce manuel olarak kaydetmeye başlamasının imkansız olduğu öngörülemeyen olaylarla ilgili verileri yakalamaktır. Profil oluşturma tetikleyicileri şunlar için kullanılabilir:

  • Performans sorunlarında hata ayıklama: ANR'leri, bellek sızıntılarını ve diğer kararlılık sorunlarını teşhis edin.
  • Kritik kullanıcı yolculuklarını optimize edin: Uygulama başlatma gibi akışları analiz edip iyileştirin.
  • Kullanıcı davranışını anlama: Kullanıcı tarafından başlatılan uygulamadan çıkışlar gibi etkinlikler hakkında bilgi edinin.

Tetikleyici oluşturma

Aşağıdaki kodda, TRIGGER_TYPE_APP_FULLY_DRAWN tetikleyicisine nasıl kaydolacağınız ve bu tetikleyiciye nasıl sıklık sınırlaması uygulayacağınız gösterilmektedir.

Kotlin

fun recordWithTrigger() {
    val profilingManager = applicationContext.getSystemService(ProfilingManager::class.java)

    val triggers = ArrayList<ProfilingTrigger>()

    val triggerBuilder = ProfilingTrigger.Builder(ProfilingTrigger.TRIGGER_TYPE_APP_FULLY_DRAWN)
        .setRateLimitingPeriodHours(1)

    triggers.add(triggerBuilder.build())

    val mainExecutor: 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(mainExecutor, resultCallback)
    profilingManager.addProfilingTriggers(triggers)

}

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 mainExecutor = 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(mainExecutor, resultCallback);
  profilingManager.addProfilingTriggers(triggers);

}

Kod şu adımları gerçekleştirir:

  1. Yöneticiyi alma: ProfilingManager hizmetini alır.
  2. Tetikleyici tanımlama: TRIGGER_TYPE_APP_FULLY_DRAWN için ProfilingTrigger oluşturur. Bu etkinlik, uygulama başlatma işleminin tamamlandığını ve etkileşimli olduğunu bildirdiğinde gerçekleşir.
  3. Sıklık sınırları belirleme: Bu tetikleyiciye (setRateLimitingPeriodHours(1)) 1 saatlik sıklık sınırı uygular. Bu, uygulamanın saatte birden fazla başlangıç profili kaydetmesini engeller.
  4. Dinleyiciyi kaydetme: Sonucu işleyen geri çağırmayı tanımlamak için registerForAllProfilingResults yöntemini çağırır. Bu geri çağırma, kaydedilen profilin yolunu getResultFilePath() aracılığıyla alır.
  5. Tetikleyici ekle: addProfilingTriggers kullanarak tetikleyici listesini ProfilingManager ile kaydeder.
  6. Etkinliği tetikle: reportFullyDrawn() işlevini çağırır. Bu işlev, sistem arka plan izlemesinin çalıştığını ve sıklık sınırlayıcı kotasının mevcut olduğunu varsayarak profil toplama işlemini tetikleyen TRIGGER_TYPE_APP_FULLY_DRAWN etkinliğini sisteme gönderir. Bu isteğe bağlı adım, uygulamanızın bu tetikleyici için reportFullyDrawn() yöntemini çağırması gerektiğinden uçtan uca bir akışı gösterir.

İzi alma

Sistem, tetikleyici tabanlı profilleri diğer profillerle aynı dizine kaydeder. Tetiklenen izlerin dosya adı şu biçimdedir:

profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>

ADB'yi kullanarak dosyayı çekebilirsiniz. Örneğin, ADB kullanarak örnek kodla yakalanan sistem izini almak için aşağıdaki gibi bir komut kullanabilirsiniz:

adb pull /data/user/0/com.example.sampleapp/files/profiling/profile_trigger_1_2025-05-06-14-12-40.perfetto-trace

Bu izleri görselleştirme hakkında ayrıntılı bilgi için Profil oluşturma verilerini alma ve analiz etme başlıklı makaleyi inceleyin.

Arka planda izlemenin işleyiş şekli

Tetikleyiciden önceki verileri yakalamak için işletim sistemi, periyodik olarak arka planda izleme başlatır. Bu arka plan izleme etkin durumdayken bir tetikleyici gerçekleşirse ve uygulamanız bu tetikleyiciye kayıtlıysa sistem, izleme profilini uygulamanızın dizinine kaydeder. Profil, tetikleyiciye yol açan bilgileri içerir.

Profil kaydedildikten sonra sistem, registerForAllProfilingResults yöntemine sağlanan geri çağırma işlevini kullanarak uygulamanızı bilgilendirir. Bu geri çağırma, yakalanan profilin yolunu sağlar. Bu yola ProfilingResult#getResultFilePath() çağrılarak erişilebilir.

Arka plan izleme anlık görüntülerinin işleyiş şeklini gösteren diyagram. Tetikleyici etkinlikten önce verileri yakalayan bir halka arabellek gösteriliyor.
Şekil 1: Arka plan izleme anlık görüntülerinin işleyiş şekli.

Sistem, cihaz performansı ve pil ömrü üzerindeki etkiyi azaltmak için arka plan izlerini sürekli olarak çalıştırmaz. Bunun yerine örnekleme yöntemini kullanır. Sistem, belirli bir zaman aralığında (minimum ve maksimum süreyle) rastgele bir arka plan izleme başlatır. Bu izlerin rastgele aralıklarla yerleştirilmesi, tetikleyici kapsamını iyileştirir.

Sistem tarafından tetiklenen profillerin sistem tarafından tanımlanan maksimum boyutu vardır. Bu nedenle, halka arabellek kullanırlar. Arabellek dolduğunda yeni izleme verileri en eski verilerin üzerine yazılır. Şekil 1'de gösterildiği gibi, yakalanan bir iz, arabellek dolarsa arka plan kaydının tamamını kapsamayabilir. Bunun yerine, tetikleyiciye yol açan en son etkinliği temsil eder.

Tetikleyiciye özel sıklık sınırlaması uygulama

Yüksek frekanslı tetikleyiciler, uygulamanızın sıklık sınırlayıcı kotasını hızla tüketebilir. Sıklık sınırlayıcıyı daha iyi anlamak için Sıklık sınırlayıcının işleyiş şekli başlıklı makaleyi incelemenizi öneririz. Tek bir tetikleyici türünün kotanızı tüketmesini önlemek için tetikleyiciye özel sıklık sınırlaması uygulayabilirsiniz.

ProfilingManager, uygulama tarafından tanımlanan tetikleyiciye özel sıklık sınırlamasını destekler. Bu sayede, mevcut sıklık sınırlayıcıya ek olarak zamana dayalı başka bir kısıtlama katmanı ekleyebilirsiniz. Bir tetikleyici için belirli bir bekleme süresi ayarlamak üzere setRateLimitingPeriodHours API'yi kullanın. Bekleme süresi sona erdikten sonra tekrar tetikleyebilirsiniz.

Tetikleyicilerde yerel olarak hata ayıklama

Arka plan izlemeleri rastgele zamanlarda çalıştığından, tetikleyicilerde yerel olarak hata ayıklamak zordur. Test için arka plan izlemeyi zorunlu kılmak istiyorsanız aşağıdaki ADB komutunu kullanın:

adb shell device_config put profiling_testing system_triggered_profiling.testing_package_name <com.example.myapp>

Bu komut, sistemi belirtilen paket için sürekli bir arka plan izlemesi başlatmaya zorlar. Böylece, sıklık sınırlaması izin verirse her tetikleyici bir profil toplayabilir.

Yerel olarak hata ayıklama yaparken sıklık sınırlayıcıyı devre dışı bırakma gibi diğer hata ayıklama seçeneklerini de etkinleştirebilirsiniz. Daha fazla bilgi için Yerel profil oluşturma için hata ayıklama komutları başlıklı makaleyi inceleyin.