Bu bölümde, örnek bir izleme ile ProfilingManager kullanılarak Uygulama Yanıt Vermiyor (ANR) hatasının nasıl ayıklanacağı gösterilmektedir.
Uygulamayı ANR'leri toplayacak şekilde ayarlama
Öncelikle uygulamanızda ANR tetikleyicisi ayarlayın:
public void addANRTrigger() { ProfilingManager profilingManager = getApplicationContext().getSystemService( ProfilingManager.class); List<ProfilingTrigger> triggers = new ArrayList<>(); ProfilingTrigger.Builder triggerBuilder = new ProfilingTrigger.Builder( ProfilingTrigger.TRIGGER_TYPE_ANR); triggers.add(triggerBuilder.build()); Executor mainExecutor = Executors.newSingleThreadExecutor(); Consumer<ProfilingResult> resultCallback = profilingResult -> { // Handle uploading trace to your back-end }; profilingManager.registerForAllProfilingResults(mainExecutor, resultCallback); profilingManager.addProfilingTriggers(triggers); }
ANR izini yakalayıp yükledikten sonra Perfetto kullanıcı arayüzünde açın.
İzlemeyi analiz etme
ANR, izlemeyi tetiklediğinden izlemenin, sistem uygulamanızın ana iş parçacığında yanıt vermeme durumu algıladığında sona erdiğini bilirsiniz. Şekil 1'de, uygulamanızın kullanıcı arayüzünde uygun şekilde etiketlenmiş olan ana iş parçacığına nasıl gideceğiniz gösterilmektedir.
Şekil 2'de gösterildiği gibi, izlemenin sonu ANR'nin zaman damgasıyla eşleşir.
İzleme, ANR oluştuğunda uygulamanın çalıştırdığı işlemleri de gösterir.
Özellikle uygulama, handleNetworkResponse izleme diliminde kod çalıştırdı. Bu dilim, MyApp:SubmitButton diliminin içindeydi. 1,48 saniye CPU süresi kullanıldı (Şekil 3).
Hata ayıklama için şu anda yalnızca ANR anındaki yığın izlemelere güveniyorsanız ANR'yi, profil kaydı tamamlandığında bitmemiş olan handleNetworkResponse izleme diliminde çalışan koda tamamen yanlış bir şekilde atfedebilirsiniz. Ancak, pahalı bir işlem olmasına rağmen 1, 48 saniye tek başına ANR'yi tetiklemek için yeterli değildir. Bu yöntemden önce ana iş parçacığını neyin engellediğini anlamak için daha geriye bakmanız gerekir.
ANR'nin nedenini aramak için bir başlangıç noktası belirlemek üzere, Choreographer#doFrame 551275 dilimine karşılık gelen kullanıcı arayüzü iş parçacığı tarafından oluşturulan son kareyi incelemeye başlıyoruz. ANR ile sonuçlanan MyApp:SubmitButton dilimi başlatılmadan önce büyük gecikme kaynakları yok (Şekil 4).
Engellemeyi anlamak için uzaklaştırarak MyApp:SubmitButton
dilimin tamamını inceleyin. Şekil 4'te gösterildiği gibi, iş parçacığı durumlarında önemli bir ayrıntı fark edeceksiniz: İş parçacığı, zamanın% 75'ini (6,7 saniye) Sleeping durumunda, yalnızca% 24'ünü ise Running durumunda geçiriyor.
Bu, ANR'nin temel nedeninin hesaplama değil, bekleme olduğunu gösterir. Bir düzen bulmak için uyku zamanlarını tek tek inceleyin.
İlk üç uyku aralığı (Şekil 6-8) neredeyse aynıdır ve her biri yaklaşık 2 saniye sürer. Dördüncü uykudaki aykırı değer (Şekil 9) 0,7 saniyedir. Tam olarak 2 saniyelik bir süre, bilgi işlem ortamında nadiren tesadüf olur. Bu durum, rastgele kaynak çekişmesinden ziyade programlanmış bir zaman aşımını işaret eder. Son uyku, beklediği işlem başarılı olduğu için ileti dizisinin bekleme işlemini tamamlamasından kaynaklanıyor olabilir.
Bu hipoteze göre, uygulama, kullanıcı tarafından tanımlanan 2 saniyelik zaman aşımına birden fazla kez ulaşıyor ve sonunda başarılı oluyordu. Bu durum, ANR'yi tetikleyecek kadar gecikmeye neden oluyordu.
Bunu doğrulamak için MyApp:SubmitButton izleme bölümüyle ilişkili kodu inceleyin:
private static final int NETWORK_TIMEOUT_MILLISECS = 2000; public void setupButtonCallback() { findViewById(R.id.submit).setOnClickListener(submitButtonView -> { Trace.beginSection("MyApp:SubmitButton"); onClickSubmit(); Trace.endSection(); }); } public void onClickSubmit() { prepareNetworkRequest(); boolean networkRequestSuccess = false; int maxAttempts = 10; while (!networkRequestSuccess && maxAttempts > 0) { networkRequestSuccess = performNetworkRequest(NETWORK_TIMEOUT_MILLISECS); maxAttempts--; } if (networkRequestSuccess) { handleNetworkResponse(); } } boolean performNetworkRequest(int timeoutMiliseconds) { // ... } // ... } public void handleNetworkResponse() { Trace.beginSection("handleNetworkResponse"); // ... Trace.endSection(); }
Kod, bu hipotezi doğrular. onClickSubmit yöntemi, kullanıcı arayüzü iş parçacığında 2.000 ms'lik sabit kodlanmış bir NETWORK_TIMEOUT_MILLISECS ile ağ isteği yürütür.
En önemlisi, while döngüsünde çalışır ve 10 kez yeniden denenir.
Bu özel izlemede, kullanıcının ağ bağlantısı muhtemelen zayıftı. İlk üç deneme başarısız oldu ve üç kez 2 saniyelik zaman aşımı yaşandı (toplam 6 saniye).
Dördüncü deneme 0, 7 saniye sonra başarılı oldu ve kodun handleNetworkResponse'ya geçmesine izin verildi. Ancak birikmiş bekleme süresi, ANR'yi zaten tetiklemişti.
Çeşitli gecikme sürelerine sahip ağla ilgili işlemleri ana iş parçacığında yürütmek yerine arka plan iş parçacığına yerleştirerek bu tür ANR'lerden kaçının. Bu sayede, bağlantı zayıf olsa bile kullanıcı arayüzü yanıt vermeye devam eder ve bu tür ANR'ler tamamen ortadan kalkar.