অ্যাপ্লিকেশন সাড়া না দিলে (ANR) সমস্যা ট্রিগার হয়, যখন অ্যাপ্লিকেশনের UI থ্রেড ৫ সেকেন্ডের বেশি সময় ধরে সাড়া দেয় না। আপনি ANR এবং ANR ডায়াগনসিস সম্পর্কে
Android ডকুমেন্টেশন থেকে
আরও জানতে পারবেন।
এছাড়াও, Crashlytics নির্দিষ্ট সমস্যাযুক্ত থ্রেড শনাক্ত করতে সাহায্য করতে পারে। আমরা
ANR বিশ্লেষণ করি এবং তারপরে,
DevOps ও এনগেজমেন্ট > Crashlytics ড্যাশবোর্ডে, আমরা ANR কীভাবে ডিবাগ করতে হয় সেই বিষয়ে ইঙ্গিত দিতে
প্রযোজ্য থ্রেড ট্যাগ করি।
এই পৃষ্ঠার নিম্নলিখিত বিভাগগুলি প্রতিটি ANR ট্যাগের অর্থ ব্যাখ্যা করে, সেই ট্যাগ সহ একটি
ANR উদাহরণ দেখায় এবং ANR ডিবাগ করার জন্য একটি সাজেস্ট করা সমাধান প্রদান করে।
Triggered ANR
কোনও থ্রেড অনেকক্ষণ ধরে ব্লক হয়ে থাকলে এবং ANR ট্রিগার করলে, সেটিকে
এই Triggered ANR ট্যাগ দিয়ে অ্যানোটেট করা হয়।
সমস্যাযুক্ত থ্রেডটি অ্যাপের মূল থ্রেড হতে পারে অথবা কোনও থ্রেড
উত্তর না দিলে সেটিও হতে পারে। তবে, Triggered ANR হিসেবে ট্যাগ করা থ্রেডটি ANR-এর আসল কারণ হতেও পারে আবার নাও হতে পারে।
এইসব ANR-এর সমস্যা সমাধান ও ডিবাগ করার জন্য ইনসাইট প্রদান করতে,
Crashlytics ANR-এ জড়িত থাকা অন্য যেকোনও থ্রেডকেও ট্যাগ করে। এই পৃষ্ঠার
নিম্নলিখিত বিভাগগুলিতে, থ্রেডে প্রয়োগ করা যেতে পারে এমন অন্যান্য ট্যাগ সম্পর্কে
জানুন।
Deadlocked
যেসব থ্রেড ডেডলকে জড়িয়ে পড়েছে বলে দেখা গেছে এবং যার ফলে ANR হয়েছে, সেগুলিকে এই Deadlocked ট্যাগ দিয়ে
অ্যানোটেট করা হয়।
ডেডলক তখন হয় যখন কোনও থ্রেড অপেক্ষারত অবস্থায় থাকে কারণ প্রয়োজনীয়
রিসোর্স অন্য একটি থ্রেড হোল্ড করে থাকে, যেটিও প্রথম থ্রেডের হোল্ড করা রিসোর্সের জন্য
অপেক্ষা করে। অ্যাপের মূল থ্রেড এই অবস্থায় থাকলে, ANR হওয়ার সম্ভাবনা
থাকে।
উদাহরণ দেখুন
ডেডলকে জড়িত দুটি থ্রেড এখানে দেওয়া হল:
main (unknown): tid=1 systid=1568
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.getPackage(PackageManagerService.java:22701)
com.android.server.pm.PackageManagerService$PackageManagerInternalImpl.filterOnlySystemPackages(PackageManagerService.java:22787)
...
com.android.server.SystemServer.main(SystemServer.java:368)
java.lang.reflect.Method.invoke(Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:517)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:934)
ActivityManager (unknown): tid=21 systid=1902
com.android.server.pm.PackageManagerService.getPackageSetting(PackageManagerService.java:23618)
com.android.server.pm.PackageManagerService.getPackageUid(PackageManagerService.java:4542)
...
android.os.Handler.handleCallback(Handler.java:907)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:216)
android.os.HandlerThread.run(HandlerThread.java:67)
com.android.server.ServiceThread.run(ServiceThread.java:44)
সাজেশন
ডেডলকে জড়িত থ্রেডগুলি দেখুন এবং সেইসব থ্রেড দ্বারা অর্জিত রিসোর্স/লক চেক করুন।
সম্ভাব্য সমাধানের জন্য
ডেডলক এবং
ডেডলক প্রতিরোধকারী অ্যালগরিদম
দেখুন।
IO Root blocking
যেসব থ্রেড ধীরে ধীরে I/O অপারেশন এক্সিকিউট করছিল এবং
Triggered ANR থ্রেডকে ব্লক করে রেখেছিল, সেগুলিকে
IO Root blocking ট্যাগ দিয়ে চিহ্নিত করা হয়। যদি
Triggered ANR থ্রেড অন্য থ্রেড দ্বারা ব্লক করা না থাকে,
তাহলে IO Root blocking থ্রেডটিও একটি
Root blocking থ্রেড।
উদাহরণ দেখুন
Thread main(THREAD_STATE_TIMED_WAITING)
sun.misc.Unsafe.park( Unsafe.java:0 )
java.util.concurrent.locks.LockSupport.parkNanos( LockSupport.java:230 )
android.database.sqlite.SQLiteConnectionPool.waitForConnection( SQLiteConnectionPool.java:756 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
Thread main(THREAD_STATE_NATIVE_WAITING)
Syscall
art::ConditionVariable::WaitHoldingLocks(art::Thread*)
art::GoToRunnable(art::Thread*)
art::JniMethodEnd(unsigned int, art::Thread*)
libcore.io.Linux.fdatasync( Linux.java:0 )
libcore.io.ForwardingOs.fdatasync( ForwardingOs.java:105 )
...
java.io.RandomAccessFile.write( RandomAccessFile.java:559 )
...
android.app.ActivityThread.main( ActivityThread.java:8192 )
সাজেশন
সাধারণত, আপনার অ্যাপের মূল
থ্রেডে বেশি খরচ সাপেক্ষ I/O অপারেশন চালানো উচিত নয়। মূল থ্রেড
IO Root blocking হলে, আপনি মূল থ্রেডে
হচ্ছে এমন কোনও অনিচ্ছাকৃত I/O অপারেশন শনাক্ত করতে
স্ট্রিক্ট মোড
ব্যবহার করতে পারেন।
Root blocking
Triggered ANR হিসেবে ট্যাগ করা থ্রেডকে ব্লক করা যেকোনও থ্রেডকে
Root blocking ট্যাগ দিয়ে অ্যানোটেট করা হয়। কোনও থ্রেডকে
Root blocking ও
Triggered ANR, দুটি হিসেবেই ট্যাগ করা হলে, অন্য কোনও থ্রেড
সেটি ব্লক করে না।
অন্য থ্রেডের জন্য কোনও Triggered ANR থ্রেড অপেক্ষা করলে (সম্ভবত
ট্রানজিটিভভাবে), সেটি
Root blocking। কোনও থ্রেড ANR-এর মূল কারণ হওয়ার
পিছনে বিভিন্ন কারণ থাকতে পারে।
উদাহরণ দেখুন
থ্রেডের অবস্থার উপর ভিত্তি করে এখানে কয়েকটি উদাহরণ দেওয়া হল:
Thread main(THREAD_STATE_RUNNABLE)
android.os.Parcel.createTypedArray( Parcel.java:3086 )
android.content.pm.PackageInfo.<init>( PackageInfo.java:546 )
...
android.app.ActivityThread$H.handleMessage( ActivityThread.java:2166 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:246 )
android.app.ActivityThread.main( ActivityThread.java:8633 )
Thread main(THREAD_STATE_BLOCKED)
DBHelper.runOnDB( DBHelper.java:97 )
DBHelper.runDb( DBHelper.java:125 )
...
java.lang.reflect.Method.invoke( Method.java:0 )
EventBus.invokeSubscriber( EventBus.java:510 )
postToSubscription( EventBus.java:437 )
...
android.os.Handler.handleCallback( Handler.java:938 )
android.os.Handler.dispatchMessage( Handler.java:99 )
android.os.Looper.loop( Looper.java:268 )
android.app.ActivityThread.main( ActivityThread.java:7904 )
সাজেশন
মূল থ্রেডে CPU-ইনটেনসিভ কাজ কমান। CPU-এর উপর বেশি চাপ পড়ে এমন টাস্ক পারফর্ম করার জন্য
ওয়ার্কার বা ব্যাকগ্রাউন্ড থ্রেড ব্যবহার করুন।
মূল থ্রেডে ডেটাবেস থেকে লোড করার মতো I/O ইনটেনসিভ কাজ কমান।
Unknown root cause
কোনও থ্রেডকে Unknown root cause ট্যাগ করা হয় যদি
সেটি ANR ট্রিগার করা থ্রেড হয় কিন্তু ANR হওয়ার সময়
সেটি প্রসেসে নিষ্ক্রিয় থাকে। Crashlytics-এর কাছে মূল কারণ নির্ধারণ করার জন্য
পর্যাপ্ত তথ্য নেই। এই ANR কেন হয়েছে তার কোনও স্পষ্ট কারণ নেই।
উদাহরণ দেখুন
Thread main(THREAD_STATE_NATIVE_WAITING) __epoll_pwait
android::Looper::pollInner(int)
android::Looper::pollOnce(int, int*, int*, void**)
android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)
android.os.MessageQueue.nativePollOnce( MessageQueue.java:0 )
android.os.MessageQueue.next( MessageQueue.java:335 )
android.os.Looper.loop( Looper.java:193 )
android.app.ActivityThread.main( ActivityThread.java:8019 )
সাজেশন
কীভাবে ANR প্রতিরোধ করা যায় সেই বিষয়ে সাধারণ পরামর্শ অনুসরণ করুন। যেমন, আপনার কোডে এমন জায়গা শনাক্ত করুন যেখানে অ্যাপের মূল থ্রেড
৫ সেকেন্ডের বেশি সময় ধরে ব্যস্ত থাকতে পারে।
Waiting for binder call
যেসব থ্রেড বাইন্ডার কলের জন্য অপেক্ষা করছিল এবং
Triggered ANR থ্রেডকে ব্লক করে রেখেছিল, সেগুলিকে
Waiting for binder call ট্যাগ দিয়ে অ্যানোটেট করা হয়। যদি
Triggered ANR থ্রেড অন্য থ্রেড দ্বারা ব্লক না করা হয়,
তাহলে Waiting for binder call থ্রেডটিও একটি
Root blocking থ্রেড।
উদাহরণ দেখুন
Thread main(THREAD_STATE_NATIVE_WAITING)
syscall
android::IPCThreadState::talkWithDriver(bool)
android::IPCThreadState::waitForResponse(android::Parcel*, int*)
android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int)
android.os.BinderProxy.transactNative( BinderProxy.java:0 )
android.os.BinderProxy.transact( BinderProxy.java:540 )
android.app.IActivityManager$Stub$Proxy.getContentProvider( IActivityManager.java:5945 )
android.app.ActivityThread.acquireProvider( ActivityThread.java:7138 )
android.app.ActivityThread$H.handleMessage( ActivityThread.java:1982 )
android.os.Handler.dispatchMessage( Handler.java:106 )
android.os.Looper.loop( Looper.java:236 )
android.app.ActivityThread.main( ActivityThread.java:8037 )
সাজেশন
বাইন্ডার কলের লেটেন্সি যেহেতু অনুমান করা যায় না, তাই বাইন্ডার কলকে
I/O অপারেশনের মতো বিবেচনা করুন এবং সম্ভব হলে সেগুলি মূল থ্রেডে করবেন না। বাইন্ডার কল ট্রিগার করে এমন কোড (এর মধ্যে প্ল্যাটফর্ম API কলও পড়ে যেগুলি
বাইন্ডার ট্রানজ্যাকশন তৈরি করে) ব্যাকগ্রাউন্ড থ্রেডে সরান অথবা মূল থ্রেড থেকে কল করা
এড়ানো না গেলে ফলাফল ক্যাশে করুন।