ANR'leri teşhis etme ve düzeltme

Bir Android uygulamasının kullanıcı arayüzü iş parçacığı çok uzun süre engellendiğinde sistem, "Uygulama yanıt vermiyor" (ANR) hatası gönderir. Bu sayfada, farklı türlerdeki ANR'ler, bunların nasıl teşhis edileceği ve düzeltmeyle ilgili öneriler açıklanmaktadır. Listelenen tüm varsayılan zaman aşımı süreleri AOSP ve Pixel cihazlar içindir. Bu süreler OEM'ye göre değişebilir.

ANR'lerin nedenini belirlerken sistem ve uygulama sorunlarını ayırt etmenin faydalı olduğunu unutmayın.

Sistem kötü durumdayken aşağıdaki sorunlar ANR'lere neden olabilir:

  • Sistem sunucusundaki geçici sorunlar, genellikle hızlı olan bağlayıcı çağrılarının yavaşlamasına neden olur.
  • Sistem sunucusuyla ilgili sorunlar ve cihazın yüksek yükü, uygulama iş parçacıklarının planlanmamasına neden olur.

Kullanabiliyorsanız sistem ve uygulama sorunlarını ayırt etmenin iyi bir yolu Perfetto izlerini kullanmaktır:

  • Ana iş parçacığının planlanıp planlanmadığını görmek için Perfetto'daki iş parçacığı durumu izine bakarak iş parçacığının çalışıp çalışmadığını veya çalıştırılabilir olup olmadığını kontrol edin.
  • Kilit çekişmesi gibi sorunlar için system_server iş parçacıklarına bakın.
  • Yavaş bağlayıcı çağrıları için varsa yanıt dizisine bakarak neden yavaş olduğunu görün.

Giriş gönderme zaman aşımı

Giriş dağıtımı ANR'leri, uygulamanın ana iş parçacığı bir giriş etkinliğine (ör. kaydırma veya tuşa basma) zamanında yanıt vermediğinde ortaya çıkar. Giriş gönderme zaman aşımları gerçekleştiğinde uygulama ön planda olduğundan, bu zaman aşımları neredeyse her zaman kullanıcı tarafından görülebilir ve etkilerini azaltmak çok önemlidir.

Varsayılan zaman aşımı süresi: 5 saniye.

Giriş dağıtımı ANR'leri genellikle ana iş parçacığındaki sorunlardan kaynaklanır. Ana ileti dizisi, kilit edinmeyi beklerken engellendiyse tutan ileti dizisi de dahil olabilir.

Giriş gönderme ANR'lerini önlemek için aşağıdaki en iyi uygulamaları izleyin:

  • Ana iş parçacığında engelleme veya uzun süren işlemler gerçekleştirmeyin. Ana iş parçacığındaki yanlışlıkla yapılan etkinlikleri yakalamak için StrictMode kullanmayı deneyin.
  • Ana iş parçacığı ile diğer iş parçacıkları arasındaki kilit çekişmesini en aza indirin.
  • Ana iş parçacığında kullanıcı arayüzü dışındaki işleri (ör. yayınları işleme veya hizmetleri çalıştırma) en aza indirin.

Genel nedenler

Giriş gönderme ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler aşağıda verilmiştir.

Neden Ne olur? Önerilen düzeltmeler
Bağlayıcı çağrısı yavaş Ana iş parçacığı uzun bir senkron bağlayıcı çağrısı yapıyor. API'nin sahibiyseniz aramayı ana iş parçacığından çıkarın veya aramayı optimize etmeyi deneyin.
Çok sayıda ardışık bağlayıcı çağrısı Ana iş parçacığı, çok sayıda ardışık senkron bağlayıcı çağrısı yapıyor. Bağlayıcı çağrılarını sıkı bir döngüde yapmayın.
G/Ç'yi engelleme Ana iş parçacığı, veritabanı veya ağ erişimi gibi engelleyici G/Ç çağrısı yapıyor. Tüm engelleme G/Ç'lerini ana ileti dizisinden taşıyın.
Kilit anlaşmazlığı Ana iş parçacığı, kilit edinmeyi beklerken engellendi. Ana iş parçacığı ile diğer iş parçacığı arasındaki kilit çekişmesini azaltın. Diğer iş parçacığındaki yavaş kodu optimize edin.
Pahalı çerçeve Tek bir karede çok fazla öğe oluşturulması, ciddi takılmaya neden olur. Çerçeveyi oluşturmak için daha az çalışın. n2 algoritmalarını kullanmayın. Kaydırma veya sayfalama gibi işlemler için verimli bileşenler kullanın. Örneğin, Jetpack Paging kitaplığı.
Başka bir bileşen tarafından engellendi Yayın alıcısı gibi farklı bir bileşen çalışıyor ve ana iş parçacığını engelliyor. Kullanıcı arayüzüyle ilgili olmayan işleri mümkün olduğunca ana iş parçacığının dışına taşıyın. Yayın alıcılarını farklı bir iş parçacığında çalıştırın.
GPU takılması GPU askısı, oluşturmanın engellenmesine ve dolayısıyla giriş dağıtımı ANR'sine neden olan bir sistem veya donanım sorunudur. Ne yazık ki, genellikle uygulama tarafında düzeltme olmaz. Mümkünse sorun gidermek için donanım ekibiyle iletişime geçin.

Hata ayıklama

Google Play Console veya Firebase Crashlytics'te ANR kümesi imzasını inceleyerek hata ayıklamaya başlayın. Küme genellikle ANR'ye neden olduğundan şüphelenilen en üstteki çerçeveleri içerir.

Aşağıdaki akış şemasında, giriş zaman aşımı dağıtımı ANR'sinin nedeninin nasıl belirleneceği gösterilmektedir.

Şekil 1. Giriş gönderme ANR'sinin nasıl hata ayıklanacağı.

Play vitals, bu yaygın ANR nedenlerinden bazılarını tespit edebilir ve hatalarını ayıklamanıza yardımcı olabilir. Örneğin, önemli veriler kilitlenme anlaşmazlığı nedeniyle ANR oluştuğunu tespit ederse ANR Analizleri bölümünde sorunu ve önerilen düzeltmeyi özetleyebilir.

Şekil 2. Play vitals ANR algılama

Odaklanılmış pencere yok

Dokunma gibi etkinlikler, isabet testi temelinde doğrudan ilgili pencereye gönderilirken tuşlar gibi etkinlikler için hedef gerekir. Bu hedef, odaklanılan pencere olarak adlandırılır. Ekran başına yalnızca bir odaklanmış pencere vardır ve bu pencere genellikle kullanıcının o anda etkileşimde bulunduğu penceredir. Odaklanmış bir pencere bulunamazsa giriş, no-focused-window ANR (Odaklanmış pencere yok ANR) hatasına neden olur. Odaklanılmamış pencere ANR'si, giriş dağıtımı ANR'sidir.

Varsayılan zaman aşımı süresi: 5 saniye.

Genel nedenler

Odaklanılmamış pencere ANR'leri genellikle aşağıdaki sorunlardan birinden kaynaklanır:

  • Uygulama çok fazla işlem yapıyor ve ilk kareyi çizmek için çok yavaş.
  • Ana pencereye odaklanılamıyor. Bir pencere FLAG_NOT_FOCUSABLE ile işaretlenirse kullanıcı, pencereye tuş veya düğme etkinlikleri gönderemez.

Kotlin

override fun onCreate(savedInstanceState: Bundle) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}

Yayın alıcı zaman aşımı

Yayın alıcı ANR'si, yayın alıcı bir yayını zamanında işlemediğinde meydana gelir. Senkron alıcılar veya goAsync() işlevini çağırmayan alıcılar için zaman aşımı, onReceive() işlevinin zamanında tamamlanmadığı anlamına gelir. goAsync() işlevini çağıran veya eşzamansız alıcılar için zaman aşımı, PendingResult.finish() işlevinin zamanında çağrılmadığı anlamına gelir.

Yayın alıcısı ANR'leri genellikle şu ileti dizilerinde meydana gelir:

  • Sorun yavaş uygulama başlatma ise ana ileti dizisi.
  • Sorun yavaş onReceive() kod ise yayın alıcısını çalıştıran iş parçacığı.
  • Sorun yavaş goAsync() yayın kodundan kaynaklanıyorsa yayın çalışanı iş parçacıkları.

Yayın alıcısı ANR'lerini önlemek için aşağıdaki en iyi uygulamaları kullanın:

  • Uygulama, yayını işlemek için başlatıldığında uygulama başlangıcı, ANR zaman aşımına dahil edildiğinden hızlı olmalıdır.
  • goAsync() kullanılıyorsa PendingResult.finish()'nin hızlıca çağrıldığından emin olun. Bu, senkron yayın alıcılarla aynı ANR zaman aşımına tabidir.
  • goAsync() kullanılıyorsa çalışan iş parçacıklarının diğer uzun süren veya engelleyici işlemlerle paylaşılmadığından emin olun.
  • Ana iş parçacığında çalışan kullanıcı arayüzü kodunun engellenmesini önlemek için yayın alıcılarını ana olmayan bir iş parçacığında çalıştırmak üzere registerReceiver() kullanmayı düşünebilirsiniz.

Zaman aşımı süreleri

Yayın alma zaman aşımı süreleri, ön plan amacının işaretinin ayarlanıp ayarlanmadığına ve platform sürümüne bağlıdır.

Amaç türü Android 13 ve önceki sürümler Android 14 ve sonraki sürümler

Ön plan öncelikli intent

(FLAG_RECEIVER_FOREGROUND ayarlanmış)

10 saniye

İşlemin CPU'ya aç olup olmadığına bağlı olarak 10-20 saniye

Arka plan önceliği intent'i

(FLAG_RECEIVER_FOREGROUND ayarlanmadı)

60 saniye

İşlemin CPU'ya aç olup olmamasına bağlı olarak 60-120 saniye

FLAG_RECEIVER_FOREGROUND işaretinin ayarlanıp ayarlanmadığını anlamak için ANR konusundaki "flg=" ifadesini bulun ve 0x10000000 işaretinin varlığını kontrol edin. Bu bit ayarlanırsa niyetin FLAG_RECEIVER_FOREGROUND ayarlanmış demektir ve bu nedenle zaman aşımı daha kısadır.

Kısa yayın zaman aşımı (10-20 saniye) içeren örnek ANR konusu:

Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }

Uzun yayın zaman aşımı (60-120 saniye) içeren örnek ANR konusu:

Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }

Yayın süreleri nasıl ölçülür?

Yayın süresi ölçümü, yayın system_server kaynağından uygulamaya gönderildiğinde başlar ve uygulama yayını işlemeyi bitirdiğinde sona erer. Uygulama işlemi zaten çalışmıyorsa ANR zaman aşımı süresi içinde soğuk başlatma da yapması gerekir. Bu nedenle, yavaş uygulama başlatma, yayın alıcısı ANR'lerine neden olabilir.

Aşağıdaki şekilde, yayın alıcısı ANR zaman çizelgesinin belirli uygulama süreçleriyle nasıl uyumlu olduğu gösterilmektedir.

Şekil 3. Yayın alıcı ANR zaman çizelgesi.

ANR zaman aşımı ölçümü, alıcı yayını işlemeyi bitirdiğinde sona erer. Bunun tam olarak ne zaman gerçekleşeceği, alıcının senkron mu yoksa asenkron mu olduğuna bağlıdır.

  • Eşzamanlı alıcılar için ölçüm, onReceive() döndüğünde durur.
  • Asenkron alıcılar için ölçüm, PendingResult.finish() çağrıldığında durur.
Şekil 4. Eşzamanlı ve eşzamansız alıcılar için ANR zaman aşımı ölçümü uç noktaları.

Genel nedenler

Yayın alıcısı ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler aşağıda verilmiştir.

Neden Uygulandığı yer Ne oldu? Önerilen düzeltme
Yavaş uygulama başlatma Tüm alıcılar Uygulamanın baştan başlatılması çok uzun sürdü. Yavaş uygulama başlatmayı optimize edin.
onReceive() planlanmadı Tüm alıcılar Yayın alıcısı iş parçacığı başka işlerle meşguldü ve onReceive() yöntemini başlatamadı. Alıcı iş parçacığında uzun süren görevler gerçekleştirmeyin (veya alıcıyı özel iş parçacığına taşımayın).
onReceive() yavaş Tüm alıcılar, ancak esas olarak eşzamanlı olanlar onReceive() yöntemi başlatıldı ancak engellendi veya yavaş olduğu için zamanında tamamlanmadı. Yavaş alıcı kodunu optimize edin.
Eşzamansız alıcı görevleri planlanmadı goAsync() alıcılar onReceive() yöntemi, çalışmayı engellenmiş bir çalışan iş parçacığı havuzunda yürütmeye çalıştığı için çalışma hiç başlamadı. Yavaş veya engelleyici çağrıları optimize edin ya da yayın çalışanları ile diğer uzun süren görevler için farklı iş parçacıkları kullanın.
Çalışanlar yavaş veya engellenmiş goAsync() alıcılar Yayın işlenirken çalışan iş parçacığı havuzunda bir yerde engelleme veya yavaş işlem oluştu. Bu nedenle, PendingResult.finish zamanında aranmadı. Yavaş async alıcı kodunu optimize edin.
PendingResult.finish adlı kişiyi aramayı unuttum goAsync() alıcılar Kod yolunda finish() işlevi eksik. finish() öğesinin her zaman çağrıldığından emin olun.

Hata ayıklama

Küme imzasına ve ANR raporuna göre, alıcının üzerinde çalıştığı iş parçacığını ve ardından eksik olan veya yavaş çalışan kodu bulabilirsiniz.

Aşağıdaki akış çizelgesinde, bir yayın alıcısı ANR'sinin nedeninin nasıl belirleneceği gösterilmektedir.

Şekil 5. Yayın alıcısı ANR'sinde nasıl hata ayıklanır?

Alıcı kodunu bulma

Google Play Console, ANR imzasında alıcı sınıfını ve yayın amacını gösterir. Aşağıdakileri kontrol edin:

  • cmp=<receiver class>
  • act=<broadcast_intent>

Aşağıda bir yayın alıcısı ANR imzası örneği verilmiştir:

com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }

onReceive() yöntemini çalıştıran iş parçacığını bulun.

Özel bir işleyici belirtmek için Context.registerReceiver kullanıyorsanız bu işleyiciyi çalıştıran iş parçacığıdır. Aksi takdirde, ana ileti dizisidir.

Örnek: Eşzamansız alıcı görevleri planlanmıyor

Bu bölümde, yayın alıcısı ANR'sinin nasıl hata ayıklanacağına dair bir örnek açıklanmaktadır.

ANR imzası aşağıdaki gibi görünüyor:

com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }

İmzaya göre yayın amacı android.accounts.LOG_ACCOUNTS_CHANGED ve alıcı sınıfı com.example.app.MyReceiver.

Alıcı kodundan, "BG Thread [0,1,2,3]" iş parçacığı havuzunun bu yayını işlemek için ana işi yaptığını belirleyebilirsiniz. Yığın dökümlerine baktığınızda, dört arka plan (BG) iş parçacığının da aynı düzene sahip olduğunu görebilirsiniz: getDataSync engelleme çağrısı çalıştırıyorlar. Tüm arka plan iş parçacıkları meşgul olduğundan yayın zamanında işlenemedi ve bu durum ANR'ye yol açtı.

BG Thread #0 (tid=26) Waiting

at jdk.internal.misc.Unsafe.park(Native method:0)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture:563)
at com.google.common.util.concurrent.ForwardingFuture.get(ForwardingFuture:68)
at com.example.app.getDataSync(<MyClass>:152)

...

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.android.libraries.concurrent.AndroidExecutorsModule.lambda$withStrictMode$5(AndroidExecutorsModule:451)
at com.google.android.libraries.concurrent.AndroidExecutorsModule$$ExternalSyntheticLambda8.run(AndroidExecutorsModule:1)
at java.lang.Thread.run(Thread.java:1012)
at com.google.android.libraries.concurrent.ManagedPriorityThread.run(ManagedPriorityThread:34)

There are several approaches to fix the issue:

  • Find out why getDataSync is slow and optimize.
  • Don't run getDataSync on all four BG threads.
  • More generally, ensure that the BG thread pool isn't saturated with long-running operations.
  • Use a dedicated thread pool for goAsync worker tasks.
  • Use an unbounded thread pool instead of the bounded BG thread pool

Example: slow app startup

A slow app startup can cause several types of ANRs, especially broadcast receiver and execute service ANRs. The cause of an ANR is likely slow app startup if you see ActivityThread.handleBindApplication in the main thread stacks.

Execute service timeout

An execute service ANR happens when the app's main thread doesn't start a service in time. Specifically, a service doesn't finish executing onCreate() and onStartCommand() or onBind() within the timeout period.

Default timeout period: 20 seconds for foreground service; 200 seconds for background service. The ANR timeout period includes the app cold start, if necessary, and calls to onCreate(), onBind(), or onStartCommand().

To avoid execute service ANRs, follow these general best practices:

  • Make sure that app startup is fast, since it's counted in the ANR timeout if the app is started to run the service component.
  • Make sure that the service's onCreate(), onStartCommand(), and onBind() methods are fast.
  • Avoid running any slow or blocking operations on the main thread from other components; these operations can prevent a service from starting quickly.

Common causes

The following table lists common causes of execute service ANRs and suggested fixes.

Cause What Suggested fix
Slow app startup The app takes too long to perform a cold start. Optimize slow app start.
Slow onCreate(), onStartCommand(), or onBind() The service component's onCreate(), onStartCommand(), or onBind() method takes too long to execute on the main thread. Optimize slow code. Move slow operations off the critical path where possible.
Not scheduled (main thread blocked before onStart()) The app's main thread is blocked by another component before the service can be started. Move other component's work off the main thread. Optimize other component's blocking code.

How to debug

From the cluster signature and ANR report in Google Play Console or Firebase Crashlytics, you can often determine the cause of the ANR based on what the main thread is doing.

The following flow chart describes how to debug an execute service ANR.

Figure 6. How to debug an execute service ANR.

If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:

  1. Find the service component class in the ANR signature. In Google Play Console, the service component class is shown in the ANR signature. In the following example ANR details, it's com.example.app/MyService.

    com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly
    Executing service com.example.app/com.example.app.MyService
    
  2. Determine whether the slow or block operation is part of app startup, the service component, or elsewhere by checking for the following important function call(s) in the main threads.

    Function call(s) in main thread stacks What it means
    android.app.ActivityThread.handleBindApplication App was starting up, so the ANR was caused by slow app start.

    <ServiceClass>.onCreate()

    [...]

    android.app.ActivityThread.handleCreateService

    Service was being created, so the ANR was likely caused by slow onCreate() code.

    <ServiceClass>.onBind()

    [...]

    android.app.ActivityThread.handleBindService

    Service was being bound, so the ANR was likely caused by slow onBind() code.

    <ServiceClass>.onStartCommand()

    [...]

    android.app.ActivityThread.handleServiceArgs

    Service was being started, so the ANR was likely caused by slow onStartCommand() code.

    For example, if the onStartCommand() method in the MyService class is slow, the main threads will look like this:

    at com.example.app.MyService.onStartCommand(FooService.java:25)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4820)
    at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2289)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8176)
    at java.lang.reflect.Method.invoke(Native method:0)
    

    Önemli işlev çağrılarından herhangi birini göremiyorsanız başka olasılıklar da vardır:

    • Hizmet çalışıyor veya kapatılıyor. Bu durumda yığınlar çok geç alınır. Bu durumda, ANR'yi yanlış pozitif olarak değerlendirip yoksayabilirsiniz.
    • Yayın alıcısı gibi farklı bir uygulama bileşeni çalışıyordur. Bu durumda, ana iş parçacığı bu bileşende engellenmiş olabilir ve hizmetin başlatılması engellenir.
  3. Önemli bir işlev çağrısı görüyorsanız ve ANR'nin genel olarak nerede gerçekleştiğini belirleyebiliyorsanız yavaş işlemi bulmak için ana iş parçacığı yığınlarının geri kalanını kontrol edin ve bu işlemi optimize edin veya kritik yoldan kaldırın.

  4. Hizmetler hakkında daha fazla bilgi için aşağıdaki sayfalara bakın:

    İçerik sağlayıcı yanıt vermiyor

    Uzak bir içerik sağlayıcı, bir sorguya yanıt vermek için zaman aşımı süresinden daha uzun süre beklerse ve sonlandırılırsa içerik sağlayıcı ANR'si oluşur.

    Varsayılan zaman aşımı süresi: İçerik sağlayıcı tarafından ContentProviderClient.setDetectNotResponding kullanılarak belirtilir. ANR zaman aşımı süresi, uzak bir içerik sağlayıcı sorgusunun çalışması için gereken toplam süreyi içerir. Bu süre, uzak uygulama zaten çalışmıyorsa soğuk başlatma süresini de kapsar.

    İçerik sağlayıcı ANR'lerini önlemek için aşağıdaki en iyi uygulamaları izleyin:

    • Uygulama, içerik sağlayıcıyı çalıştırmak için başlatıldığında uygulama başlatma işleminin hızlı olduğundan emin olun. Bu işlem, ANR zaman aşımı süresine dahil edilir.
    • İçerik sağlayıcı sorgularının hızlı olduğundan emin olun.
    • Uygulamanın bağlayıcı iş parçacıklarının tümünü engelleyebilecek çok sayıda eşzamanlı engelleme bağlayıcı çağrısı yapmayın.

    Genel nedenler

    Aşağıdaki tabloda, içerik sağlayıcı ANR'lerinin yaygın nedenleri ve önerilen düzeltmeler listelenmektedir.

    Neden Ne olur? Sinyal Önerilen düzeltme
    İçerik sağlayıcı sorgusunun yavaş olması İçerik sağlayıcının yürütmesi çok uzun sürüyor veya engelleniyor. android.content.ContentProvider$Transport.query çerçevesi, bağlayıcı iş parçacığında yer alıyor. İçerik sağlayıcı sorgusunu optimize edin. Binder iş parçacığını neyin engellediğini öğrenin.
    Yavaş uygulama başlatma İçerik sağlayıcının uygulamasının başlatılması çok uzun sürüyor. ActivityThread.handleBindApplication çerçevesi ana iş parçacığındadır. Uygulama başlatma işlemini optimize edin.
    Bağlayıcı iş parçacığı tükenmesi: Tüm bağlayıcı iş parçacıkları meşgul Tüm bağlayıcı iş parçacıkları diğer eşzamanlı isteklere hizmet etmekle meşgul olduğundan içerik sağlayıcı bağlayıcı çağrısı çalıştırılamıyor. Uygulama başlatılmıyor, tüm bağlayıcı iş parçacıkları meşgul ve içerik sağlayıcı çalışmıyor. Bağlayıcı dişlerindeki yükü azaltır. Yani, daha az sayıda senkron giden bağlayıcı çağrısı yapın veya gelen çağrıları işlerken daha az iş yapın.

    Hata ayıklama

    Google Play Console veya Firebase Crashlytics'teki küme imzası ve ANR raporunu kullanarak bir içerik sağlayıcı ANR'sini ayıklamak için ana iş parçacığının ve bağlayıcı iş parçacıklarının ne yaptığına bakın.

    Aşağıdaki akış şeması, içerik sağlayıcı ANR'sinin nasıl ayıklanacağını açıklamaktadır:

    7.şekil İçerik sağlayıcı ANR'sini ayıklama

    Aşağıdaki kod snippet'inde, yavaş içerik sağlayıcı sorgusu nedeniyle engellendiğinde bağlayıcı iş parçacığının nasıl göründüğü gösterilmektedir. Bu durumda, içerik sağlayıcı sorgusu bir veritabanı açılırken kilit beklemektedir.

    binder:11300_2 (tid=13) Blocked
    
    Waiting for osm (0x01ab5df9) held by at com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers:182)
    at com.example.app.MyClass.blockingGetOpenDatabase(FooClass:171)
    [...]
    at com.example.app.MyContentProvider.query(MyContentProvider.java:915)
    at android.content.ContentProvider$Transport.query(ContentProvider.java:292)
    at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:107)
    at android.os.Binder.execTransactInternal(Binder.java:1339)
    at android.os.Binder.execTransact(Binder.java:1275)
    

    Aşağıdaki kod snippet'i, uygulamanın yavaş başlatılması nedeniyle ana iş parçacığı engellendiğinde nasıl göründüğünü gösterir. Bu durumda, uygulama başlangıcı, Dagger ilk kullanıma hazırlama sırasında kilit çekişmesi nedeniyle yavaş olur.

    main (tid=1) Blocked
    
    [...]
    at dagger.internal.DoubleCheck.get(DoubleCheck:51)
    - locked 0x0e33cd2c (a qsn)at dagger.internal.SetFactory.get(SetFactory:126)
    at com.myapp.Bar_Factory.get(Bar_Factory:38)
    [...]
    at com.example.app.MyApplication.onCreate(DocsApplication:203)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1316)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
    at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2235)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:205)
    at android.os.Looper.loop(Looper.java:294)
    at android.app.ActivityThread.main(ActivityThread.java:8170)
    at java.lang.reflect.Method.invoke(Native method:0)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
    

    Yavaş iş yanıtı

    Yavaş iş yanıtı ANR'si, uygulamanın JobService.onStartJob() veya JobService.onStopJob() öğesine yanıt vermesi ya da JobService.setNotification() kullanarak bildirim sağlaması çok uzun sürdüğünde meydana gelir. Bu durum, uygulamanın ana iş parçacığının başka bir işlem yaparken engellendiğini gösterir.

    Sorun JobService.onStartJob() veya JobService.onStopJob() ile ilgiliyse ana iş parçacığında neler olduğuna bakın. JobService.setNotification() ile ilgili bir sorun varsa en kısa sürede aradığınızdan emin olun. Bildirimi sağlamadan önce çok fazla işlem yapmayın.

    İleti Dizisi Oluşturma İhlalini Görüntüleme

    Compose yöntemini deneyin
    Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir.

    Uygulamanız bir görünümü arka plan iş parçacığında değiştirirse görünüm hiyerarşisinin dahili durumunda yarış durumu tetiklenebilir. Bu ihlal, ana (UI) iş parçacığının senkron mesajları yürütmesini engelleyerek kritik kararlılık sorunlarına yol açabilir:

    • Sessiz kullanıcı arayüzü donmaları: Uygulamanın kullanıcı arayüzü, kullanıcı girişine yanıt vermeyi durdurur.
    • Kilitlenmeler: Uygulama, illegalStateException ile kilitlenebilir.
    • ANR'ler: Sistem, ANR zaman aşımını tetikleyebilir.

    Bu iş parçacığı ihlali, ana iş parçacığının boşta göründüğü ANR yığın izlemelerinin (ör. "nativePollOnce" veya "main thread idle" içinde yakalanan) temel nedenlerinden biridir.

    Senkronizasyon engeli sızıntısı

    Görünümler, durumları değiştirilerek (örneğin, TextView.setText, View.setVisibility çağrılarak) dolaylı olarak veya View.invalidate ya da View.requestLayout çağrılarak doğrudan geçersiz kılınabilir. Bir görünüm geçersiz kılındığında, ViewRootImpl kullanıcı arayüzü durumunu güncellemek için ölçüm, düzen ve çizim işlemlerini gerçekleştirmek üzere bir geçiş planlar.

    1. Çapraz Geçişleri Planlama: ViewRootImpl, kullanıcı arayüzü iş parçacığının MessageQueue'ına bir senkronizasyon engeli göndererek çapraz geçiş (düzen ve çizim geçişi) planlar. Bu engel, kullanıcı arayüzü düzeninin öncelikli olması için normal ileti işlemeyi duraklatır.
    2. Yarışma durumu: Birden fazla iş parçacığı aynı anda bir görünümü geçersiz kılmaya çalıştığında bu geçişi planlamak için yarışırlar. Her iki iş parçacığı da senkronizasyon engeli'ni başarıyla ekleyebilir ancak çerçeve yalnızca birinin jetonunu saklar.
    3. Kullanıcı arayüzü dondurma: Geçiş yürütüldüğünde yalnızca tek bir kaydedilmiş bariyer kaldırılır. İkincil, "sızdırılmış" engeller süresiz olarak kuyrukta kalır ve kullanıcı arayüzü iş parçacığının eşzamanlı mesajları işlemesini kalıcı olarak engeller.

    Bu nedenle kullanıcı arayüzü donar. MessageQueue, sızdırılan engellerin ötesindeki senkron iletileri işleyemediğinden ana iş parçacığı boşta durma durumuna girer. Bu sorun genellikle yığın izinde nativePollOnce ile ANR olarak ortaya çıkar.

    Görünüm dizisi oluşturma ihlallerini önlemek için aşağıdaki en iyi uygulamaları izleyin:

    • Yalnızca görünüm hiyerarşisini oluşturduğunuz ileti dizisinde View nesnelerle etkileşim kurun. Bu etkileşimler arasında width veya height gibi özellikleri okuma ya da TextView's text gibi özellikleri ayarlama yer alır. Bu, neredeyse her zaman ana veya kullanıcı arayüzü ileti dizisidir.
    • Görünümlere erişirken kullanıcı arayüzü iş parçacığında çalıştığınızı garanti edemiyorsanız bunu yapmanın güvenli olmadığını varsayın. Örneğin, arka plan çalışması için Coroutines kullanıyorsanız View nesnelerini değiştirmeden önce ana dağıtıcıya geçmeniz gerekir.

    lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
        val data = myRepository.getData()
        withContext(Dispatchers.Main) { // Switch context to Main
            myTextView.text = data.title
        }
    }

    Android, en iyi uygulamaları uygulamanıza yardımcı olmak için kullanıcı arayüzü iş parçacığına diğer iş parçacıklarından erişmenin çeşitli yollarını sunar:

    Popüler resim yükleyiciler, reaktif uzantı çerçeveleri, etkinlik veri yolu kitaplıkları ve diğer iş parçacığı çözümleri genellikle ana iş parçacığında belirli etkinlikleri gözlemlemenin yollarını sunar. Bu, görünümlerin durumunu alması ve ayarlaması gereken gözlemciler ve etkinlik işleyiciler için yararlıdır.

    Hata ayıklama

    Android 17, geliştirme sırasında görünüm iş parçacığı ihlallerini belirlemenize, izlemenize ve çözmenize yardımcı olacak yeni araçlar sunar.

    1. Uyumluluk çerçevesi araçları

    Uyumluluk çerçevesi araçları, uygulama geliştiricilerin geliştirici seçeneklerini veya ADB'yi kullanarak davranış değişikliklerini tek tek etkinleştirmesine ve devre dışı bırakmasına olanak tanır. Aşağıdaki adımları uygulayarak görünümdeki iş parçacığı ihlali davranış değişikliklerini etkinleştirebilir veya devre dışı bırakabilirsiniz:

    1. Uygulamanızın hata ayıklanabilir bir sürümünü Android 17 veya sonraki bir sürümün yüklü olduğu bir cihaza yükleyin.
    2. Cihazınızın Ayarlar uygulamasını açın ve Sistem > Gelişmiş > Geliştirici seçenekleri > Uygulama Uyumluluğuyla İlgili Değişiklikler'e gidin.
    3. Listeden uygulamanızı seçin.
    4. Değişiklik listesinde ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS anahtarını bulup etkinleştirin.

    İşareti ADB kullanarak da açıp kapatabilirsiniz:

    $ adb shell am compat enable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
    $ adb shell am compat disable ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APIS <your.package.name>
    

    Bu işaretin etkinleştirilmesi, bir View API'si yanlış iş parçacığından her çağrıldığında uygulamanın istisna oluşturmasına ve kilitlenmesine neden olur. Bu sayede, görünüm iş parçacığı ihlali sorunlarını yakalamanıza ve düzeltmenize yardımcı olur.

    2. CalledFromWrongThreadListener API'si

    Ayrıca, uygunsuz iş parçacığı erişimini programatik olarak algılamak için genel View#registerCalledFromWrongThreadListener API'sini de uygulayabilirsiniz.

    • Telemetri ve İzleme: Bu dinleyici, bir View API'si yanlış iş parçacığından çağrıldığında uygulamanızın geri çağırma işlemleri almasına olanak tanır. Böylece telemetriyi kaydetmek ve hataları izlemek kolaylaşır.
    • Satır İçi Yürütme: İşleyici satır içinde çağrılır. Bu sayede, ihlal gerçekleştiği anda tam yığın izlemeyi (stack trace) yakalayıp inceleyebilirsiniz.
    android {
       //...
       compileSdk = 37
    }
    

    val listener = object : View.CalledFromWrongThreadListener {
        override fun onCalledFromWrongThread() {
            // Handle the issue, e.g. crash if this is a dev build, or log an event
            // e.g. Log.d(TAG, "CalledFromWrongThread: ${Exception().stackTraceToString()}")
            // Unregister the listener to avoid redundant notifications for the same issue
            View.unregisterCalledFromWrongThreadListener(this)
        }
    }
    View.registerCalledFromWrongThreadListener(listener)

    nativePollOnce

    ANR yığınlarında "nativePollOnce" veya "message queue idle" çerçevesini görüyorsanız bu genellikle yanıt vermediğinden şüphelenilen iş parçacığının aslında boşta olduğu ve looper mesajlarını beklediği anlamına gelir. Google Play Console'da ANR ayrıntıları şu şekilde görünür:

    Native method - android.os.MessageQueue.nativePollOnce
    Executing service com.example.app/com.example.app.MyService
    

    Örneğin, ana iş parçacığı boşta ise yığınlar şu şekilde görünür:

    "main" tid=1 NativeMain threadIdle
    
    #00  pc 0x00000000000d8b38  /apex/com.android.runtime/lib64/bionic/libc.so (__epoll_pwait+8)
    #01  pc 0x0000000000019d88  /system/lib64/libutils.so (android::Looper::pollInner(int)+184)
    #02  pc 0x0000000000019c68  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
    #03  pc 0x000000000011409c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
    at android.os.MessageQueue.nativePollOnce (Native method)
    at android.os.MessageQueue.next (MessageQueue.java:339)  at android.os.Looper.loop (Looper.java:208)
    at android.app.ActivityThread.main (ActivityThread.java:8192)
    at java.lang.reflect.Method.invoke (Native method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:626)
    at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1015)
    

    Yanıt vermediği düşünülen iş parçacığının boşta olmasının birkaç nedeni vardır:

    • Sistem genelinde sorun. İşlem, sistemin aşırı yüklenmesi veya sistem sunucusundaki bir sorun nedeniyle planlanmadı.
    • Geç yığın dökümü. ANR tetiklenmesi ile yığınların dökülmesi arasındaki kısa süre içinde iş parçacığı kurtarılır. Android 13'teki Pixel'lerde gecikme süresi yaklaşık 100 ms'dir ancak 1 saniyeyi aşabilir. Android 14'teki Pixel cihazlarda gecikme genellikle 10 ms'nin altındadır.
    • İleti dizisinin yanlış ilişkilendirilmesi. ANR imzası oluşturmak için kullanılan iş parçacığı, ANR'ye neden olan asıl yanıt vermeyen iş parçacığı değildi.
    • İş parçacığı oluşturma ihlalini görüntüleyin. Uygulamanız bir arka plan iş parçacığında görünümü değiştirirse görünümün iç kısımlarında, kullanıcı arayüzü iş parçacığı görevlerinin çalışmasını engelleyen bir yarış durumu tetiklenebilir.

    "nativePollOnce" ANR'sinin temel tetikleyicileri ANR türüne göre değiştiğinden, belirli ANR kategorisini teşhis etmek, uygulamanızdaki sorunu çözmek için uygulanabilir adımları belirlemenize yardımcı olabilir.

    Kategori Neden Önerilen düzeltme
    Giriş gönderme zaman aşımı Sistem genelinde sorun
    Geç bellek dökümü
    Herhangi bir işlem yapmanız gerekmez.
    Odaklanılmış pencere yok Sistem genelinde sorun
    Geç yığın dökümü
    İş parçacığı ihlalini görüntüleme
    Görünüm iş parçacığı ihlalleri için kod tabanını kontrol edin.
    Yayın alıcı zaman aşımı Geç yığın dökümü
    Sistem genelinde sorun
    Thread'in yanlış ilişkilendirilmesi
    Thread'in ihlalini görüntüleme
    Yığın dökümündeki ilgili iş parçacıklarını inceleyin.
    Kod tabanında görünüm iş parçacığı ihlali olup olmadığını kontrol edin.
    Hizmet yürütme zaman aşımı Geç yığın dökümü
    Sistem genelinde sorun
    İş parçacığı ihlalini görüntüle
    Görünüm iş parçacığı ihlalleri için kod tabanını kontrol edin.
    İçerik sağlayıcı yanıt vermiyor Geç yığın dökümü
    Sistem genelinde sorun
    İş parçacığı yanlış ilişkilendirmesi
    Yığın dökümündeki ilgili iş parçacıklarını inceleyin.

    NativePollOnce ANR'lerini analiz etmek için önerilen adımlar şunlardır:

    1. Aşırı sistem yükü: Yanıt vermeme durumunun temel nedeni olarak sistem genelinde CPU, bellek veya G/Ç kıtlığı gibi genel cihaz kaynak baskısını değerlendirin.
    2. İş parçacığı yanlış ilişkilendirmesi: Çalışan ve bağlayıcı iş parçacıklarını kilitlenmeler, ana iş parçacığını etkileyen kilit çekişmesi veya eşzamansız bileşenleri (ör. goAsync()) işleyen askıda kalan arka plan iş parçacıkları açısından denetleyin.
    3. İş parçacığı ihlallerini görüntüleme: Arka plan iş parçacıklarını, yasa dışı kullanıcı arayüzü görünümü hiyerarşisi değişiklikleri için tarayın. Bu değişiklikler, MessageQueue'da bir senkronizasyon engelinin yetim kalmasına ve tüm eşzamanlı mesajların kalıcı olarak engellenmesine neden olabilir.

    Yığın çerçevesi yok

    Bazı ANR raporları, ANR'nin bulunduğu yığınları içermez. Bu da ANR raporu oluşturulurken yığın dökümünün başarısız olduğu anlamına gelir. Yığın çerçevelerinin eksik olmasının birkaç olası nedeni vardır:

    • Yığını almak çok uzun sürüyor ve zaman aşımına uğruyor.
    • Yığınlar alınmadan önce süreç sonlandırıldı.
    [...]
    
    --- CriticalEventLog ---
    capacity: 20
    timestamp_ms: 1666030897753
    window_ms: 300000
    
    libdebuggerd_client: failed to read status response from tombstoned: timeout reached?
    
    ----- Waiting Channels: pid 7068 at 2022-10-18 02:21:37.<US_SOCIAL_SECURITY_NUMBER>+0800 -----
    
    [...]
    

    Yığın çerçeveleri içermeyen ANR'ler, küme imzası veya ANR raporundan işleme alınamaz. Hata ayıklamak için uygulamanın diğer kümelerine bakın. Sorun yeterince büyükse genellikle yığın çerçevelerinin bulunduğu kendi kümesi olur. Diğer bir seçenek de Perfetto izlerine bakmaktır.

    Bilinen sorunlar

    ANR tetiklenmeden önce yayın işleme sürecini tamamlamak için uygulamanızın sürecinde bir zamanlayıcı tutmak, sistemin ANR'leri eşzamansız olarak izlemesi nedeniyle doğru şekilde çalışmayabilir.