Tetikleyici tabanlı profil oluşturma

Android 16 (API düzeyi 36) ve sonraki sürümlerde ProfilingManager, Uygulama Yanıt Vermiyor (ANR) hataları, yetersiz bellek (OutOfMemoryError) kilitlenmeleri veya uygulama başlatma etkinlikleri gibi sistem tetikleyicilerine yanıt olarak profilleri otomatik olarak yakalamanıza olanak tanır. Bu olayların çoğunun sahada ne zaman gerçekleşeceğini tahmin edemeyeceğiniz için kaydı önceden manuel olarak başlatmak pratik değildir. Tetikleyici tabanlı profilleme sayesinde sistem, yakalama işlemini yönetir ve elde edilen profili uygulamanıza gönderir. Böylece şunları yapabilirsiniz:

  • Kararlılık sorunlarında hata ayıklama: Öngörülemeyen ANR'leri ve bellek sızıntılarını teşhis edin.
  • Kritik kullanıcı yolculuklarını (CUJ) optimize etme: Uygulama başlatma (TRIGGER_TYPE_COLD_START ve TRIGGER_TYPE_APP_FULLY_DRAWN) gibi akışları analiz edin.
  • Kullanıcı davranışını anlama: Kullanıcı tarafından başlatılan uygulamadan çıkışlar gibi etkinlikleri inceleyin.

Kullanılabilir tetikleyicilerin tam listesi için ProfilingTrigger sayfasına bakın.

Tetikleyici türleri

Tetikleyiciler, etkinlik gerçekleştiğinde sistemin profili nasıl yakaladığına göre farklılık gösterir.

Arka plan izini kullanan tetikleyiciler

ANR gibi birçok tetikleyici, daha önceki bir sorunun sonucudur. Sistem ANR'yi algıladıktan sonra izleme başlatıldığında, ANR'ye neden olan engelleyici işlem kaçırılır. Etkinliğe yol açan etkinliği yakalamak için aşağıdaki tetikleyiciler, sistemin etkin arka plan izinin anlık görüntüsünü kaydeder. Etkinlik gerçekleştiğinde arka planda izleme çalışmıyorsa profil toplanmaz:

Yeni bir yakalama başlatan tetikleyiciler

Aşağıdaki tetikleyiciler arka plan izine bağlı değildir. Bunun yerine sistem, etkinlik gerçekleştiğinde yeni bir profil yakalama işlemi başlatır:

Yakalama davranışının anormalliğe göre değiştiği tetikleyiciler

Aşağıdaki anormallik tetikleyicileri için yakalanan profil türü (etkin arka plan izinin anlık görüntüsünü kaydetme veya yeni bir yakalama başlatma) ve sıklık sınırlama davranışı, sistem tarafından algılanan belirli anormalliğe bağlıdır:

Tetikleyici oluşturma

Aşağıdaki kodda, TRIGGER_TYPE_APP_FULLY_DRAWN tetikleyicisine nasıl kaydolacağınız ve bu tetikleyici için nasıl bekleme dönemi ayarlayacağınız gösterilmektedir.

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

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şlemini tamamladığını ve etkileşimli olduğunu bildirmek için etkinlik tarafından başlatılan bir baştan başlatma sırasında reportFullyDrawn() yöntemini çağırdığında gerçekleşir.
  3. Tetikleyici bekleme süresi ayarlama: Sistem sıklık sınırlayıcısına ek olarak setRateLimitingPeriodHours kullanarak bu tetikleyiciye 1 saatlik bekleme süresi uygular. Bu bekleme süresi, 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 ekleme: addProfilingTriggers kullanarak tetikleyici listesini ProfilingManager ile kaydeder.
  6. Etkinliği tetikle: Bir sonraki kare çizildiğinde reportFullyDrawn() işlevini çağıran bir Choreographer kare geri çağırma işlevi yayınlar. Bu işlev, TRIGGER_TYPE_APP_FULLY_DRAWN etkinliğini sisteme göndererek 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 tetikler. Bu tetikleyicinin gerçekleşmesi için uygulamanızın reportFullyDrawn() yöntemini çağırdığından emin olun.

Tetikleyici yaşam döngüsü

Kayıtlı tetikleyiciler, uygulama yeniden başlatıldığında ve sistem yeniden başlatıldığında da geçerliliğini korur. Uygulamanız her başlatıldığında veya sistem yeniden başlatıldıktan sonra tetikleyicileri yeniden kaydetmeniz gerekmez. Tetikleyicileri addProfilingTriggers kullanarak kaydettikten sonra sistem, siz kaldırana veya uygulama kaldırılana kadar tetikleyicileri uygulamanız için otomatik olarak korur.

Tetikleyicilerin kaydı ne zaman iptal edilmelidir?

Kayıtlı tetikleyiciler, uygulama yeniden başlatıldığında ve sistem yeniden başlatıldığında kalıcı olduğundan, sonraki başlatmalarda addProfilingTriggers yöntemini atlamak, önceki bir oturumda kaydedilen tetikleyicileri durdurmaz. Belirli etkinlikler veya tüm etkinlikler için profil yakalamayı durdurmak istiyorsanız removeProfilingTriggersByType veya clearProfilingTriggers yöntemini açıkça çağırın.

Aşağıdaki durumlarda tetikleyicilerin kaydını iptal edin:

  • Kohortları hedefleme veya uzak işaretleri geri alma: Uzak yapılandırma veya A/B testi işaretlerini kullanarak kohortlar arasında segment profili oluşturabilirsiniz. Bir cihaz örneklenen gruptan ayrıldığında veya bir işaret devre dışı bırakıldığında tetikleyicilerin kaydını iptal edin.
  • Hata ayıklama kampanyasını tamamlama: Bir sorunu teşhis etmek veya düzeltme göndermek için yeterli profil topladıktan sonra tetikleyiciyi kaldırın. Gereksiz tetikleyicilerin kaydını iptal etmek, cihaz depolama alanını ve uygulamanızın diğer profil oluşturma istekleri için sıklık sınırlayıcı kotasını korur.

Geri çağırma yaşam döngüsü

Doğrudan profil oluşturma isteklerinin aksine, tetikleyici tabanlı profiller yalnızca registerForAllProfilingResults ile kayıtlı bir global dinleyiciye sonuç gönderir. Geri aramanızda, yakalama işlemini hangi tetikleyicinin başlattığını belirlemek için ProfilingResult.getTriggerType işlevini, kaydedilen profil dosyasını bulmak için ise ProfilingResult.getResultFilePath işlevini çağırın. Tetikleyici profil dosya adları, adb ile dosya alma ve sonuçları arka planda yükleme hakkında ayrıntılı bilgi için Profilleri alma ve yükleme başlıklı makaleyi inceleyin.

Tetikleyiciler, uygulama yeniden başlatıldığında ve sistem yeniden başlatıldığında devam etse de sonuç geri çağırma işleviniz devam etmez. Uygulama başlatma işlemi tamamlandıktan sonra geri çağırma işlevinizi arka plandaki bir Executor üzerinde kaydedin (böylece soğuk başlatmayı yavaşlatmazsınız). Bu sayede, aşağıdaki senaryoların her ikisinde de profilleri alabilirsiniz:

  • Uygulamanız çalışırken: Uygulamanızı durdurmayan veya kilitlenmesine neden olmayan tetikleyiciler için sistem, tetikleyici gerçekleştiğinde ve profil kaydedildiğinde sağlanan Executor üzerinde geri çağırma işlevinizi çağırır.
  • Uygulama sonlandırıldıktan sonra: Genellikle uygulama sonlandırmayı içeren veya bundan önce gelen tetikleyiciler (ör. TRIGGER_TYPE_ANR, TRIGGER_TYPE_OOM veya TRIGGER_TYPE_KILL_RECENTS) için ya da uygulamanız yakalama işlemi tamamlanmadan durursa sistem, profili arka planda kaydeder ve sonucu uygulama yeniden başlatma ve sistem yeniden başlatma işlemleri arasında sıraya alır. Sistem, teslim edilmemiş sıraya alınmış sonuçları 7 güne kadar saklar ve uygulamanız bir sonraki çalıştığında ve registerForAllProfilingResults yöntemini çağırdığında teslim eder.

Arka planda izlemenin işleyiş şekli

Sistem, profil oluşturma ek yükünü faydalı yapıları yakalamayla dengelemek için arka plan izlerini sürekli olarak çalıştırmaz. Bunun yerine, arka plan izlerini rastgele aralıklarla başlatarak periyodik olarak örnekleme yapar.

Sistem tarafından tetiklenen arka plan izlemeleri, sistem tarafından tanımlanan maksimum boyuta sahip bir halka arabellek kullanır. Arabellek dolduğunda yeni izleme verileri en eski verilerin üzerine yazılır. Şekil 1'de gösterildiği gibi, kayıtlı bir tetikleyici arka plan izleme etkinken ve sıklık sınırlayıcı kotası mevcutken tetiklendiğinde sistem, tetikleyiciye yol açan en son etkinliği içeren halka arabellek anlık görüntüsünü kaydeder.

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

Tetikleyiciye özel bekleme süresi ayarlama

Yüksek frekanslı tetikleyiciler, uygulamanızın sıklık sınırlayıcı kotasını hızla tüketebilir. Tek bir tetikleyici türünün kotanızı tüketmesini önlemek için sistem sıklık sınırlayıcısına ek olarak tetikleyici başına minimum bekleme süresi eklemek üzere setRateLimitingPeriodHours kullanın.

Hata ayıklama tetikleyicileri yerel olarak çalışır.

Arka plan izleri, üretimde rastgele aralıklarla çalıştığından tetikleyicileri yerel olarak test etmek için sürekli bir arka plan izi zorunlu kılınmalı ve paketiniz için sistem düzeyindeki sıklık sınırlayıcı atlanmalıdır (setRateLimitingPeriodHours ile ayarlanan tetikleyici başına bekleme süresi geçerli olmaya devam eder ve rate_limiter.disabled yalnızca uygulama tarafından yönlendirilen requestProfiling çağrıları için geçerlidir).

Arka plan izlemelerini zorla etkinleştirmek, komut satırından tetikleyicileri simüle etmek ve hizmet durumunu incelemek için kullanılan adb komutları hakkında bilgi edinmek isterseniz Yerel profil oluşturma için hata ayıklama komutları bölümündeki Tetikleyici testi için arka plan izlemelerini zorla etkinleştirme başlıklı makaleyi inceleyin.