Android অ্যাপের UI থ্রেড অনেকক্ষণ ধরে ব্লক হয়ে থাকলে, সিস্টেম একটি "অ্যাপ্লিকেশন উত্তর দিচ্ছে না" (ANR) সংক্রান্ত সমস্যা পাঠায়। এই পৃষ্ঠায় বিভিন্ন ধরনের ANR, কীভাবে সেগুলি শনাক্ত করতে হয় এবং সেগুলি সমাধান করার সাজেশন সম্পর্কে বর্ণনা করা হয়েছে। তালিকাভুক্ত সব ডিফল্ট টাইমআউট টাইম রেঞ্জ AOSP ও Pixel ডিভাইসের জন্য; এইসব সময় OEM অনুযায়ী আলাদা আলাদা হতে পারে।
মনে রাখবেন, ANR-এর কারণ নির্ধারণ করার সময়, সিস্টেম ও অ্যাপ সংক্রান্ত সমস্যার মধ্যে পার্থক্য করতে পারলে তা সহায়ক হয়।
সিস্টেমের অবস্থা খারাপ হলে, নিম্নলিখিত সমস্যাগুলি ANR-এর কারণ হতে পারে:
- সিস্টেম সার্ভারে ক্ষণস্থায়ী সমস্যার কারণে সাধারণত দ্রুত বাইন্ডার কল ধীর গতির হয়ে যায়।
- সিস্টেম সার্ভার সংক্রান্ত সমস্যা এবং ডিভাইসে বেশি লোড থাকার কারণে অ্যাপ থ্রেড শিডিউল করা যায় না।
আপনার জন্য উপলভ্য হলে, সিস্টেম ও অ্যাপ সংক্রান্ত সমস্যার মধ্যে পার্থক্য করার একটি ভাল উপায় হল Perfetto ট্রেস ব্যবহার করা:
- অ্যাপের মূল থ্রেড শিডিউল করা হয়েছে কিনা তা থ্রেড স্টেট ট্র্যাক দেখে বুঝুন। এটি চলছে নাকি চালানো যাবে তা Perfetto-তে দেখুন।
system_serverথ্রেডে লক কনটেনশন সংক্রান্ত সমস্যার দিকে নজর দিন।- ধীর বাইন্ডার কলের ক্ষেত্রে, উত্তর থ্রেড থাকলে, সেটি দেখে নিন যে কেন এটি ধীর।
ইনপুট ডিসপ্যাচ করার সময়সীমা পেরিয়ে গেছে
ইনপুট ডিসপ্যাচ ANR তখন হয় যখন অ্যাপের মূল থ্রেড কোনও ইনপুট ইভেন্টের উত্তর সময়মতো দিতে পারে না, যেমন সোয়াইপ করা বা কী প্রেস করা। ইনপুট ডিসপ্যাচ টাইম-আউট হলে যেহেতু অ্যাপটি ফোরগ্রাউন্ডে থাকে, সেটি প্রায় সবসময় ব্যবহারকারীর কাছে দৃশ্যমান হয় এবং এটি কমানো খুবই গুরুত্বপূর্ণ।
ডিফল্ট টাইম-আউট পিরিয়ড: ৫ সেকেন্ড।
ইনপুট ডিসপ্যাচ ANR সাধারণত মূল থ্রেডে সমস্যার কারণে ঘটে। লক পাওয়ার জন্য অপেক্ষা করার সময় মূল থ্রেড ব্লক হয়ে গেলে, হোল্ডার থ্রেডও জড়িত থাকতে পারে।
ইনপুট ডিসপ্যাচ ANR এড়াতে, এইসব পেশাদার পদ্ধতি অনুসরণ করুন:
- মূল থ্রেডে ব্লকিং বা দীর্ঘ সময় ধরে চলতে থাকা অপারেশন পারফর্ম করবেন না। মূল থ্রেডে আকস্মিক
অ্যাক্টিভিটি ধরতে
StrictModeব্যবহার করার কথা বিবেচনা করুন। - মূল থ্রেড ও অন্যান্য থ্রেডের মধ্যে লক কনটেনশন কমান।
- ব্রডকাস্ট বা পরিষেবা চালানোর মতো মূল থ্রেডে UI নয় এমন কাজ কমান।
সাধারণ কারণ
ইনপুট ডিসপ্যাচ ANR-এর কিছু সাধারণ কারণ ও সাজেস্ট করা সমাধান এখানে দেওয়া হল।
| কারণ | এতে কী হয় | সাজেস্ট করা সমাধান |
|---|---|---|
| বাইন্ডার কল ধীরে ধীরে করা | মূল থ্রেড একটি দীর্ঘ সিঙ্ক্রোনাস বাইন্ডার কল করে। | আপনি API-এর মালিক হলে, কলটি মূল থ্রেড থেকে সরিয়ে নিন অথবা কলটি অপ্টিমাইজ করার চেষ্টা করুন। |
| বাইন্ডার থেকে পরপর অনেক কল | মূল থ্রেড অনেক ধারাবাহিক সিঙ্ক্রোনাস বাইন্ডার কল করে। | টাইট লুপে বাইন্ডার কল পারফর্ম করবেন না। |
| I/O ব্লক করা | মূল থ্রেড, ডেটাবেস বা নেটওয়ার্ক অ্যাক্সেসের মতো ব্লকিং I/O কল করে। | ব্লকিং IO-এর সব কাজ মূল থ্রেড থেকে সরিয়ে দিন। |
| লক কনটেনশন | লক পাওয়ার জন্য অপেক্ষা করার সময় মূল থ্রেড ব্লক হয়ে যায়। | মূল থ্রেড ও অন্যান্য থ্রেডের মধ্যে লক কনটেনশন কমান। অন্য থ্রেডে ধীরে ধীরে চলা কোড অপ্টিমাইজ করুন। |
| দামী ফ্রেম | সিঙ্গেল ফ্রেমে অনেক বেশি রেন্ডার করা হচ্ছে, যার ফলে মারাত্মক জ্যাঙ্ক হচ্ছে। | ফ্রেম রেন্ডার করার জন্য কম কাজ করতে হয়। n2 অ্যালগরিদম ব্যবহার করবেন না। স্ক্রল করা বা পেজিংয়ের মতো কাজের জন্য দক্ষ কম্পোনেন্ট ব্যবহার করুন—যেমন, Jetpack পেজিং লাইব্রেরি। |
| অন্য কম্পোনেন্ট ব্লক করেছে | অন্য কোনও কম্পোনেন্ট, যেমন ব্রডকাস্ট রিসিভার, চলছে এবং মূল থ্রেড ব্লক করছে। | UI সংক্রান্ত নয় এমন কাজ যতটা সম্ভব মূল থ্রেড থেকে সরিয়ে দিন। অন্য থ্রেডে ব্রডকাস্ট রিসিভার চালান। |
| GPU হ্যাং | GPU হ্যাং হল একটি সিস্টেম বা হার্ডওয়্যার সংক্রান্ত সমস্যা যা রেন্ডারিং ব্লক করে এবং এর ফলে ইনপুট ডিসপ্যাচ ANR হয়। | সাধারণত, অ্যাপের দিক থেকে কোনও সমাধান থাকে না। সম্ভব হলে, সমস্যার সমাধান করতে হার্ডওয়্যার টিমের সাথে যোগাযোগ করুন। |
কীভাবে ডিবাগ করতে হয়
Google Play Console বা Firebase Crashlytics-এ ANR ক্লাস্টার সিগনেচার দেখে ডিবাগ করা শুরু করুন। ক্লাস্টারে সাধারণত ANR-এর কারণ হতে পারে বলে সন্দেহ করা শীর্ষ ফ্রেম থাকে।
nativePollOnce দেখুন।ইনপুট টাইমআউট ডিসপ্যাচ ANR-এর কারণ কীভাবে নির্ধারণ করতে হয় তা নিম্নলিখিত ফ্লোচার্টে দেখানো হয়েছে।
Play vitals এইসব সাধারণ ANR কারণ শনাক্ত করতে এবং তা ডিবাগ করতে সাহায্য করতে পারে। যেমন, ভিটাল যদি শনাক্ত করে যে লক কনটেনশনের কারণে ANR হয়েছে, তাহলে এটি ANR ইনসাইট বিভাগে সমস্যার সারসংক্ষেপ ও সাজেস্ট করা সমাধান দেখাতে পারে।
কোনও ফোকাস করা উইন্ডো নেই
টাচ করার মতো ইভেন্ট হিট টেস্টিংয়ের উপর ভিত্তি করে সরাসরি প্রাসঙ্গিক উইন্ডোতে পাঠানো হয়, তবে কী প্রেস করার মতো ইভেন্টের জন্য টার্গেট প্রয়োজন। এই টার্গেটকে ফোকাস করা উইন্ডো বলা হয়। প্রতিটি ডিসপ্লেতে শুধুমাত্র একটি ফোকাস করা উইন্ডো থাকে এবং এটি সাধারণত সেই উইন্ডো যার সাথে ব্যবহারকারী বর্তমানে ইন্টার্যাক্ট করছেন। ফোকাস করা উইন্ডো খুঁজে না পাওয়া গেলে, ইনপুট একটি no-focused-window ANR বাড়ায়। ফোকাস করা নেই এমন উইন্ডো ANR হল ইনপুট ডিসপ্যাচ ANR-এর একটি ধরন।
ডিফল্ট টাইম-আউট পিরিয়ড: ৫ সেকেন্ড।
সাধারণ কারণ
ফোকাস করা নেই এমন উইন্ডো সংক্রান্ত ANR সাধারণত নিম্নলিখিত সমস্যাগুলির মধ্যে কোনও একটির কারণে হয়:
- অ্যাপটি অনেক বেশি কাজ করছে এবং প্রথম ফ্রেম আঁকার জন্য খুব ধীরে চলছে।
- প্রধান উইন্ডোতে ফোকাস করা যায় না। কোনও উইন্ডোকে
FLAG_NOT_FOCUSABLEহিসেবে ফ্ল্যাগ করা হলে, ব্যবহারকারী এতে কী বা বোতাম ইভেন্ট পাঠাতে পারবেন না।
Kotlin
override fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) window.addFlags(WindowManager.LayoutParams.FLAG_FLAG_NOT_FOCUSABLE) }
জাভা
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); }
ব্রডকাস্ট রিসিভার টাইম-আউট
কোনও ব্রডকাস্ট রিসিভার সময়মতো কোনও ব্রডকাস্ট হ্যান্ডেল করতে না পারলে, ব্রডকাস্ট রিসিভার ANR হয়।
সিঙ্ক্রোনাস রিসিভার বা যেসব রিসিভার কল করে না
goAsync(), তাদের ক্ষেত্রে টাইম-আউট বলতে বোঝায় যে onReceive() নির্দিষ্ট সময়ের মধ্যে
সম্পূর্ণ হয়নি। অ্যাসিঙ্ক রিসিভার বা goAsync() কল করা রিসিভারের ক্ষেত্রে, টাইম-আউট বলতে বোঝায় যে
PendingResult.finish() সময়মতো কল করা হয়নি।
এইসব থ্রেডে ব্রডকাস্ট রিসিভার ANR প্রায়ই হয়:
- অ্যাপ চালু হতে বেশি সময় লাগলে, মূল থ্রেড।
- থ্রেড রানিং ব্রডকাস্ট রিসিভার, যদি সমস্যাটি
onReceive()কোড ধীর গতির হয়। - ব্রডকাস্ট ওয়ার্কার থ্রেড, যদি সমস্যাটি ধীরে
goAsync()ব্রডকাস্ট কোড হয়।
ব্রডকাস্ট রিসিভার ANR এড়াতে, এইসব পেশাদার পদ্ধতি অনুসরণ করুন:
- অ্যাপ স্টার্ট-আপ যাতে দ্রুত হয় তা নিশ্চিত করুন, কারণ ব্রডকাস্ট হ্যান্ডেল করার জন্য অ্যাপ চালু করা হলে, এটি ANR টাইম-আউটে গণনা করা হয়।
goAsync()ব্যবহার করা হলে,PendingResult.finish()যাতে দ্রুত কল করা হয় তা নিশ্চিত করুন। সিনক্রোনাস ব্রডকাস্ট রিসিভারের মতো একই ANR টাইমআউট এখানেও প্রযোজ্য।goAsync()ব্যবহার করা হলে, নিশ্চিত করুন যে ওয়ার্কার থ্রেড(গুলি) অন্য দীর্ঘক্ষণ ধরে চলা বা ব্লকিং অপারেশনের সাথে শেয়ার করা হয়নি।- মূল থ্রেডে রান করা UI কোড ব্লক করা এড়াতে,
registerReceiver()ব্যবহার করে নন-মূল থ্রেডে ব্রডকাস্ট রিসিভার রান করার কথা বিবেচনা করুন।
টাইমআউট পিরিয়ড
ব্রডকাস্ট পাওয়ার টাইমআউট পিরিয়ড নির্ভর করে ফোরগ্রাউন্ড ইনটেন্ট ফ্ল্যাগ সেট করা আছে কিনা এবং প্ল্যাটফর্ম ভার্সনের উপর।
| ইন্টেন্টের ধরন | Android 13 ও তার আগের যেকোনও ভার্সন | Android 14 ও তার পরের যেকোনও ভার্সন |
|---|---|---|
ফোরগ্রাউন্ড প্রায়োরিটি ইনটেন্ট ( |
১০ সেকেন্ড |
১০-২০ সেকেন্ড, প্রসেস CPU-starved কিনা তার উপর নির্ভর করে |
ব্যাকগ্রাউন্ড প্রায়োরিটি ইনটেন্ট ( |
৬০ সেকেন্ড |
৬০-১২০ সেকেন্ড, প্রসেস CPU-starved কিনা তার উপর নির্ভর করে |
FLAG_RECEIVER_FOREGROUND ফ্ল্যাগ সেট করা আছে কিনা তা বুঝতে, ANR সাবজেক্টে "flg=" দেখুন এবং 0x10000000 আছে কিনা চেক করুন। এই বিট সেট করা থাকলে, ইনটেন্টে FLAG_RECEIVER_FOREGROUND সেট করা আছে এবং সেই জন্য টাইম-আউট কম হবে।
স্বল্প ব্রডকাস্ট টাইমআউট (১০-২০ সেকেন্ড) সহ ANR বিষয়ের উদাহরণ:
Broadcast of Intent { act=android.inent.action.SCREEN_ON flg=0x50200010 }
দীর্ঘ ব্রডকাস্ট টাইমআউট (৬০-১২০ সেকেন্ড) সহ ANR বিষয়ের উদাহরণ:
Broadcast of Intent { act=android.intent.action.TIME_SET flg=0x25200010 }
সম্প্রচারের সময় কীভাবে পরিমাপ করা হয়
ব্রডকাস্টের সময়সীমা পরিমাপ করা শুরু হয় যখন ব্রডকাস্টটি
system_server থেকে অ্যাপে পাঠানো হয় এবং শেষ হয় যখন অ্যাপটি
ব্রডকাস্ট প্রসেস করা শেষ করে। অ্যাপ প্রসেস আগে থেকে না চললে, ANR টাইমআউট পিরিয়ডের মধ্যে এটিকে কোল্ড
স্টার্ট করতে হবে। তাই, অ্যাপ চালু হতে দেরি হলে
ব্রডকাস্ট রিসিভার ANR হতে পারে।
নিচের ছবিতে দেখানো হয়েছে যে ব্রডকাস্ট রিসিভার ANR টাইমলাইন নির্দিষ্ট অ্যাপ প্রসেসের সাথে অ্যালাইন করে।
প্রাপক যখন ব্রডকাস্ট প্রসেস করা শেষ করে, তখন ANR টাইমআউট পরিমাপ শেষ হয়ে যায়: এটি ঠিক কখন ঘটে তা নির্ভর করে এটি সিঙ্ক্রোনাস বা অ্যাসিঙ্ক্রোনাস রিসিভার কিনা তার উপর।
- সিনক্রোনাস রিসিভারের ক্ষেত্রে,
onReceive()রিটার্ন করলে পরিমাপ করা বন্ধ হয়ে যায়। - অ্যাসিঙ্ক্রোনাস রিসিভারের ক্ষেত্রে,
PendingResult.finish()কল করা হলে পরিমাপ করা বন্ধ হয়ে যায়।
সাধারণ কারণ
ব্রডকাস্ট রিসিভার ANR-এর কিছু সাধারণ কারণ ও সাজেস্ট করা সমাধান এখানে দেওয়া হল।
| কারণ | এগুলির জন্য প্রযোজ্য | কী ঘটেছিল | সাজেস্ট করা সমাধান |
|---|---|---|---|
| অ্যাপ ধীরে ধীরে চালু হওয়া | সব প্রাপক | অ্যাপটি কোল্ড স্টার্ট হতে অনেক সময় লেগেছে। | ধীরে ধীরে অ্যাপ চালু হওয়া অপ্টিমাইজ করা। |
onReceive() শিডিউল করা হয়নি | সব প্রাপক | ব্রডকাস্ট রিসিভার থ্রেড অন্য কাজ করতে ব্যস্ত ছিল এবং onReceive() পদ্ধতি শুরু করতে
পারেনি। | রিসিভার থ্রেডে দীর্ঘক্ষণ ধরে চলতে থাকা টাস্ক পারফর্ম করবেন না (অথবা রিসিভারকে ডেডিকেটেড থ্রেডে সরিয়ে দিন)। |
onReceive() ধীরে কাজ করছে | সব রিসিভার, তবে মূলত সিঙ্ক্রোনাস রিসিভার | onReceive() পদ্ধতি শুরু করা হয়েছিল কিন্তু
ব্লক করা বা ধীরে হওয়ার কারণে সময়মতো সম্পূর্ণ করা যায়নি। | ধীর গতির রিসিভার কোড অপ্টিমাইজ করুন। |
| এসিঙ্ক রিসিভার টাস্ক শিডিউল করা হয়নি | goAsync()
প্রাপক | onReceive() পদ্ধতিটি ব্লক করা ওয়ার্কার থ্রেড পুলে
কাজ করার চেষ্টা করেছে, তাই কাজটি কখনও শুরু হয়নি। |
ধীর গতির বা ব্লক করা কল অপ্টিমাইজ করুন অথবা ব্রডকাস্ট ওয়ার্কার বনাম অন্যান্য দীর্ঘ সময় ধরে চলা টাস্কের জন্য আলাদা থ্রেড ব্যবহার করুন। |
| ওয়ার্কারের গতি কমে যাওয়া বা ব্লক হয়ে যাওয়া | goAsync() জন প্রাপক |
ব্রডকাস্ট প্রসেস করার সময় ওয়ার্কার থ্রেড
পুলে কোথাও ব্লকিং বা ধীরে ধীরে অপারেশন হয়েছে। তাই, PendingResult.finish
-কে সময়মতো কল করা হয়নি। | ধীর গতির async রিসিভার
কোড অপ্টিমাইজ করুন। |
PendingResult.finish-এ কল করতে ভুলে যাওয়া |
goAsync() জন প্রাপক |
কোড পাথে finish()-এ কল নেই। |
finish()-কে সবসময় কল করা হচ্ছে কিনা তা নিশ্চিত করুন। |
কীভাবে ডিবাগ করতে হয়
ক্লাস্টার সিগনেচার ও ANR রিপোর্টের ভিত্তিতে, আপনি সেই থ্রেডটি খুঁজে পেতে পারবেন যা প্রাপক রান করান এবং তারপরে সেই নির্দিষ্ট কোডটি খুঁজে পাবেন যা অনুপস্থিত বা ধীরে ধীরে রান করছে।
nativePollOnce দেখুন।নিচের ফ্লো চার্ট থেকে কীভাবে ব্রডকাস্ট রিসিভার ANR-এর কারণ নির্ধারণ করতে হয় তা জানতে পারবেন।
প্রাপকের কোড খুঁজুন
Google Play Console ANR সিগনেচারে রিসিভার ক্লাস ও ব্রডকাস্ট ইনটেন্ট দেখায়। নিম্নলিখিত বিষয়গুলি দেখুন:
cmp=<receiver class>act=<broadcast_intent>
ব্রডকাস্ট রিসিভার ANR সিগনেচারের একটি উদাহরণ এখানে দেওয়া হল:
com.example.app.MyClass.myMethod
Broadcast of Intent { act=android.accounts.LOGIN_ACCOUNTS_CHANGED
cmp=com.example.app/com.example.app.MyAccountReceiver }
onReceive() মেথড রান করছে এমন থ্রেড খুঁজে বের করা
আপনি কাস্টম হ্যান্ডলার নির্দিষ্ট করতে Context.registerReceiver ব্যবহার করলে,
এটি হল সেই থ্রেড যা এই হ্যান্ডলার রান করছে। অন্যথায়, এটি হল মূল থ্রেড।
উদাহরণ: এসিঙ্ক রিসিভার টাস্ক শিডিউল করা হয়নি
এই বিভাগে, কীভাবে ব্রডকাস্ট রিসিভার ANR ডিবাগ করতে হয় তার একটি উদাহরণ দেওয়া হয়েছে।
ধরা যাক, ANR সিগনেচারটি দেখতে এইরকম:
com.example.app.MyClass.myMethod
Broadcast of Intent {
act=android.accounts.LOG_ACCOUNTS_CHANGED cmp=com.example.app/com.example.app.MyReceiver }
সিগনেচারের ভিত্তিতে, মনে হচ্ছে ব্রডকাস্ট ইনটেন্ট হল
android.accounts.LOG_ACCOUNTS_CHANGED এবং রিসিভার ক্লাস হল
com.example.app.MyReceiver।
প্রাপক কোড থেকে, আপনি নির্ধারণ করতে পারবেন যে থ্রেড পুল "BG Thread
[0,1,2,3]" এই ব্রডকাস্ট প্রসেস করার মূল কাজটি করে। স্ট্যাক
ডাম্প থেকে আপনি দেখতে পাবেন যে চারটি ব্যাকগ্রাউন্ড (BG) থ্রেডের একই প্যাটার্ন আছে:
সেগুলি একটি ব্লকিং কল, getDataSync রান করে। সব BG থ্রেড ব্যস্ত থাকার কারণে, ব্রডকাস্ট সময়মতো প্রসেস করা যায়নি, যার ফলে ANR হয়েছে।
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
getDataSyncis slow and optimize. - Don't run
getDataSyncon 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
goAsyncworker 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(), andonBind()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.
If you've determined that the execute service ANR is actionable, follow these steps to help resolve the issue:
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.MyServiceDetermine 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.handleBindApplicationApp 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 theMyServiceclass 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)আপনি গুরুত্বপূর্ণ ফাংশন কলের কোনওটি দেখতে না পেলে, আরও কয়েকটি সম্ভাবনা রয়েছে:
- পরিষেবা চলছে বা বন্ধ হয়ে যাচ্ছে, এর অর্থ হল স্ট্যাক খুব দেরিতে নেওয়া হয়েছে। এই ক্ষেত্রে, আপনি ANR-কে ফলস পজিটিভ হিসেবে উপেক্ষা করতে পারেন।
- অন্য কোনও অ্যাপ কম্পোনেন্ট চলছে, যেমন ব্রডকাস্ট রিসিভার। এই ক্ষেত্রে, এই কম্পোনেন্টে মূল থ্রেড ব্লক হয়ে যাওয়ার সম্ভাবনা থাকে, যার ফলে সার্ভিস শুরু করা যায় না।
আপনি যদি কোনও মূল ফাংশন কল দেখতে পান এবং ANR কোথায় ঘটছে তা নির্ধারণ করতে পারেন, সাধারণত, ধীর গতির অপারেশন খুঁজে পেতে এবং অপ্টিমাইজ করতে বা এটিকে গুরুত্বপূর্ণ পাথ থেকে সরিয়ে দিতে, বাকি মূল থ্রেড স্ট্যাক চেক করুন।
- অ্যাপ স্টার্ট-আপ যাতে দ্রুত হয় তা নিশ্চিত করুন, কারণ কন্টেন্ট প্রদানকারীকে চালানোর জন্য অ্যাপ চালু করা হলে এটি ANR টাইম-আউটে গণনা করা হয়।
- কন্টেন্ট প্রদানকারীর কোয়েরি দ্রুত প্রসেস করা হচ্ছে কিনা তা নিশ্চিত করুন।
- একসাথে অনেক ব্লকিং বাইন্ডার কল পারফর্ম করবেন না, এটি করলে অ্যাপের সব বাইন্ডার থ্রেড ব্লক হয়ে যেতে পারে।
- সাইলেন্ট UI ফ্রিজ: অ্যাপের UI ব্যবহারকারীর ইনপুটের উত্তর দেওয়া বন্ধ করে দেয়।
- ক্র্যাশ করা: অ্যাপটি
illegalStateExceptionসহ ক্র্যাশ করতে পারে। - ANR: সিস্টেম ANR টাইম-আউট ট্রিগার করতে পারে।
- ট্রাভার্সাল শিডিউল করা:
ViewRootImplএকটি ট্রাভার্সাল—একটি লেআউট ও ড্রয়িং পাস—শিডিউল করে UI থ্রেডেরMessageQueue-এ সিঙ্ক্রোনাইজেশন ব্যারিয়ার পোস্ট করে। এই বাধা সাধারণ মেসেজ প্রসেসিং পজ করে দেয় যাতে UI লেআউটকে অগ্রাধিকার দেওয়া যায়। - রেস কন্ডিশন: একাধিক থ্রেড একই সাথে কোনও ভিউ ভুল প্রমাণ করার চেষ্টা করলে, তারা এই ট্রাভার্সাল শিডিউল করার জন্য প্রতিযোগিতা করে। দুটি থ্রেডই হয়ত সফলভাবে সিঙ্ক্রোনাইজেশন ব্যারিয়ার ইনসার্ট করতে পারে, কিন্তু ফ্রেমওয়ার্ক শুধুমাত্র একটি থ্রেডের টোকেন স্টোর করে।
- UI ফ্রিজ: ট্রাভার্সাল এক্সিকিউট হলে, এটি শুধুমাত্র সেভ করা একটি ব্যারিয়ার সরিয়ে দেয়। সেকেন্ডারি, "লিক করা" বাধাগুলি অনির্দিষ্টকালের জন্য সারিতে থাকে, কোনও সিঙ্ক্রোনাস মেসেজ প্রসেস করা থেকে UI থ্রেডকে স্থায়ীভাবে ব্লক করে।
- আপনি যে থ্রেডে ভিউ হায়ারার্কি তৈরি করেছেন, সেখানে শুধুমাত্র
Viewঅবজেক্টের সাথে ইন্টার্যাক্ট করুন—এর মধ্যেwidthবাheight-এর মতো প্রপার্টি পড়া অথবাTextView's text-এর মতো প্রপার্টি সেট করা অন্তর্ভুক্ত— । এটি প্রায় সবসময়ই মূল বা UI থ্রেড হয়। - আপনি যদি নিশ্চিত না হন যে ভিউ অ্যাক্সেস করার সময় UI থ্রেডে রান করছেন, তাহলে ধরে নিন যে এটি করা নিরাপদ নয়। যেমন, আপনি যদি ব্যাকগ্রাউন্ডে কাজ করার জন্য
Coroutinesব্যবহার করেন, তাহলে আপনাকে অবশ্যইViewঅবজেক্ট ম্যানিপুলেট করার আগে মূল ডিসপ্যাচারে সুইচ করতে হবে। ContextCompat#getMainExecutor(android.content.Context)View.post(Runnable)Activity.runOnUiThread(Runnable)- Android 17 বা তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসে আপনার অ্যাপের একটি ডিবাগ করা যায় এমন ভার্সন ইনস্টল করুন।
- আপনার ডিভাইসের সেটিংস অ্যাপ খুলুন এবং সিস্টেম > উন্নত > ডেভেলপার বিকল্প > অ্যাপ কম্প্যাটিবিলিটি সংক্রান্ত পরিবর্তন বিকল্পে যান।
- তালিকা থেকে আপনার অ্যাপ বেছে নিন।
- পরিবর্তনের তালিকা থেকে,
ENFORCE_THREAD_CHECKS_ON_VIEW_ROOT_IMPL_APISসুইচ খুঁজে নিয়ে টগল করে চালু করুন। - টেলিমেট্রি ও ট্র্যাকিং: এই লিসনার আপনার অ্যাপকে কলব্যাক রিসিভ করার অনুমতি দেয়, যখন কোনও ভুল থ্রেড থেকে View API ইনভোক করা হয়। এর ফলে টেলিমেট্রি লগ করা এবং বাগ ট্র্যাক করা সহজ হয়ে যায়।
- ইনলাইন এক্সিকিউশন: লিসনারকে ইনলাইন বলা হয়, এর ফলে আপনি লঙ্ঘন হওয়ার সময় ঠিক স্ট্যাক ট্রেস ক্যাপচার ও পরিদর্শন করতে পারেন।
- সিস্টেম-ব্যাপী সমস্যা। সিস্টেমের উপর অত্যধিক লোড অথবা সিস্টেম সার্ভারে সমস্যার কারণে প্রসেসটি শিডিউল করা যায়নি।
- দেরিতে স্ট্যাক ডাম্প করা। ANR ট্রিগার হওয়া এবং স্ট্যাক ডাম্প করার মধ্যবর্তী স্বল্প সময়ের মধ্যে থ্রেড রিকভার করা হয়েছে। Android 13 চালু Pixel-এ লেটেন্সি প্রায় ১০০ মিলিসেকেন্ড, তবে ১ সেকেন্ডের বেশিও হতে পারে। Android 14-এ Pixel-এর লেটেন্সি সাধারণত ১০ মিলি সেকেন্ডের কম হয়।
- থ্রেড ভুল অ্যাট্রিবিউশন। ANR সিগনেচার তৈরি করতে যে থ্রেড ব্যবহার করা হয়েছে সেটি প্রকৃত রেসপন্স না করা থ্রেড নয় যা ANR-এর কারণ।
- থ্রেডিং সংক্রান্ত লঙ্ঘন দেখুন। আপনার অ্যাপ ব্যাকগ্রাউন্ড থ্রেডে কোনও ভিউ পরিবর্তন করলে, এটি ভিউয়ের ইন্টার্নালে রেস কন্ডিশন ট্রিগার করতে পারে যা UI থ্রেড টাস্ককে চলতে বাধা দেয়
- সিস্টেমের উপর বেশি চাপ: সামগ্রিকভাবে ডিভাইসের রিসোর্সের উপর চাপের মূল্যায়ন করুন, যেমন সিস্টেম-ব্যাপী সিপিইউ, মেমরি বা I/O স্টারভেশনকে প্রতিক্রিয়া না জানানোর প্রাথমিক কারণ হিসেবে বিবেচনা করুন।
- থ্রেড মিসঅ্যাট্রিবিউশন: ডেডলক,
মূল থ্রেডকে প্রভাবিত করে এমন লক কনটেনশন বা ব্যাকগ্রাউন্ড থ্রেড হ্যাং হওয়া
অ্যাসিঙ্ক্রোনাস কম্পোনেন্ট (যেমন,
goAsync()) প্রসেস করার জন্য অডিট ওয়ার্কার ও বাইন্ডার থ্রেড। - থ্রেডিং সংক্রান্ত লঙ্ঘন দেখা: বেআইনি UI ভিউ হায়রার্কি পরিবর্তনের জন্য ব্যাকগ্রাউন্ড থ্রেড স্ক্যান করে, যা MessageQueue-এ সিঙ্ক ব্যারিয়ারকে অরফ্যান করতে পারে এবং স্থায়ীভাবে সব সিঙ্ক্রোনাস মেসেজ ব্লক করতে পারে।
- স্ট্যাক নিতে অনেক সময় লাগছে এবং টাইম-আউট হয়ে যাচ্ছে।
- স্ট্যাক নেওয়ার আগেই প্রসেস বন্ধ হয়ে গেছে বা বন্ধ করে দেওয়া হয়েছে।
পরিষেবা সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত পৃষ্ঠাগুলি দেখুন:
কন্টেন্ট প্রদানকারী উত্তর দিচ্ছেন না
রিমোট কন্টেন্ট প্রদানকারী কোয়েরির উত্তর দেওয়ার জন্য টাইম-আউট পিরিয়ডের চেয়ে বেশি সময় নিলে এবং প্রসেসটি বন্ধ করে দেওয়া হলে কন্টেন্ট প্রদানকারী ANR হয়।
ডিফল্ট টাইম-আউট পিরিয়ড: কন্টেন্ট প্রদানকারীর নির্দিষ্ট করা
ContentProviderClient.setDetectNotResponding। ANR টাইমআউট পিরিয়ডের মধ্যে
রিমোট কন্টেন্ট প্রদানকারীর কোয়েরি চালানোর মোট সময় অন্তর্ভুক্ত থাকে, যার মধ্যে
রিমোট অ্যাপ আগে থেকে না চললে সেটি কোল্ড-স্টার্ট করাও অন্তর্ভুক্ত।
কন্টেন্ট প্রদানকারীর ANR এড়াতে, এইসব পেশাদার পদ্ধতি অনুসরণ করুন:
সাধারণ কারণ
নিচের টেবিলে কন্টেন্ট প্রদানকারীর ANR-এর সাধারণ কারণ এবং সাজেস্ট করা সমাধানের তালিকা দেওয়া আছে।
| কারণ | এতে কী হয় | সিগন্যাল | সাজেস্ট করা সমাধান |
|---|---|---|---|
| কন্টেন্ট প্রদানকারীর কোয়েরি ধীরে ধীরে প্রসেস করা | কন্টেন্ট প্রদানকারীকে এক্সিকিউট করতে অনেক সময় লাগে বা সেটি ব্লক করা হয়। | android.content.ContentProvider$Transport.query ফ্রেমটি
বাইন্ডার থ্রেডে আছে। |
কন্টেন্ট প্রদানকারীর কোয়েরি অপ্টিমাইজ করা। বাইন্ডার থ্রেডকে কী ব্লক করছে তা খুঁজে বের করুন। |
| অ্যাপ চালু হতে বেশি সময় লাগা | কন্টেন্ট প্রদানকারীর অ্যাপ চালু হতে অনেক বেশি সময় লাগছে। | ActivityThread.handleBindApplication ফ্রেমটি
প্রধান থ্রেডে আছে। |
অ্যাপ স্টার্ট-আপ অপ্টিমাইজ করা। |
| বাইন্ডার থ্রেড শেষ হয়ে যাওয়া—সব বাইন্ডার থ্রেড ব্যস্ত আছে | সবকটি বাইন্ডার থ্রেড অন্যান্য সিঙ্ক্রোনাস অনুরোধ পূরণ করতে ব্যস্ত থাকার ফলে কন্টেন্ট প্রদানকারী বাইন্ডার কল রান করতে পারছে না। | অ্যাপ চালু হচ্ছে না, সব বাইন্ডার থ্রেড ব্যস্ত আছে এবং কন্টেন্ট প্রোভাইডার চলছে না। | বাইন্ডার থ্রেডের উপর লোড কমান। অর্থাৎ, কম সিঙ্ক্রোনাস আউটগোয়িং বাইন্ডার কল করুন অথবা ইনকামিং কল হ্যান্ডেল করার সময় কম কাজ করুন। |
কীভাবে ডিবাগ করতে হয়
ক্লাস্টার সিগনেচার এবং Google Play Console বা Firebase Crashlytics-এ ANR রিপোর্ট ব্যবহার করে কন্টেন্ট প্রদানকারী ANR ডিবাগ করতে, মূল থ্রেড এবং বাইন্ডার থ্রেড কী করছে তা দেখুন।
নিচের ফ্লো চার্ট থেকে কীভাবে কন্টেন্ট প্রদানকারীর ANR ডিবাগ করতে হয় তা জানতে পারবেন:
নিচের কোড স্নিপেট থেকে বোঝা যায় যে কন্টেন্ট প্রদানকারীর কোয়েরি ধীরে ধীরে আসার কারণে বাইন্ডার থ্রেড ব্লক হয়ে গেলে সেটি কেমন দেখতে লাগে। এই ক্ষেত্রে, ডেটাবেস খোলার সময় কন্টেন্ট প্রদানকারী কোয়েরি লক করার জন্য অপেক্ষা করছে।
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)
অ্যাপ স্টার্ট-আপ ধীর গতির হওয়ার কারণে ব্লক করা হলে, নিম্নলিখিত কোড স্নিপেট থেকে মূল থ্রেডটি কেমন দেখতে হয় তা জানতে পারবেন। এই ক্ষেত্রে, ড্যাগার ইনিশিয়ালাইজ করার সময় লক কনটেনশনের কারণে অ্যাপ স্টার্ট-আপ ধীরে ধীরে হয়।
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)
জব রেসপন্স ধীরে ধীরে আসা
কোনও জব থেকে ধীরে ধীরে উত্তর এলে ANR হয়, এটি তখন হয় যখন অ্যাপটি
JobService.onStartJob() বা JobService.onStopJob()-এর উত্তর দিতে অনেক বেশি সময় নেয় অথবা JobService.setNotification() ব্যবহার করে বিজ্ঞপ্তি
প্রদান করতে অনেক বেশি সময় নেয়। এর থেকে বোঝা যায় যে
অ্যাপের মূল থ্রেড অন্য কিছু করার জন্য ব্লক করা আছে।
JobService.onStartJob() বা JobService.onStopJob()-এর সাথে কোনও সমস্যা হলে,
মূল থ্রেডে কী ঘটছে তা চেক করুন। এটি যদি
JobService.setNotification()-এর সাথে সম্পর্কিত সমস্যা হয়, তাহলে যত তাড়াতাড়ি সম্ভব কল করতে ভুলবেন না।
বিজ্ঞপ্তি দেখানোর আগে অনেক কাজ করবেন না।
থ্রেডিং সংক্রান্ত লঙ্ঘন দেখুন
আপনার অ্যাপ যদি ব্যাকগ্রাউন্ড থ্রেডে কোনও ভিউ পরিবর্তন করে, তাহলে এটি ভিউ হায়ারার্কির ইন্টার্নাল স্টেটে রেস কন্ডিশন ট্রিগার করতে পারে। এই লঙ্ঘন কোনও সিঙ্ক্রোনাস মেসেজ এক্সিকিউট করা থেকে মূল (UI) থ্রেডকে ব্লক করতে পারে, যার ফলে গুরুতর স্থিতিশীলতা সংক্রান্ত সমস্যা হতে পারে:
এই থ্রেডিং লঙ্ঘন হল ANR স্ট্যাক ট্রেসের অন্যতম মূল কারণ যেখানে মূল থ্রেডটি নিষ্ক্রিয় বলে মনে হয় (যেমন, "nativePollOnce" বা "main thread idle" ক্যাপচার করা হয়েছে)।
সিঙ্ক ব্যারিয়ার লিক
ভিউয়ের স্টেট পরিবর্তন করে (যেমন,
TextView.setText, View.setVisibility কল করে) অথবা সরাসরি
View.invalidate বা View.requestLayout কল করে ভিউ বাতিল করা যেতে পারে। কোনও ভিউ বাতিল করা হলে,
ViewRootImpl UI স্টেট আপডেট করার জন্য
মেজারমেন্ট, লেআউট ও ড্রয়িং পারফর্ম করতে ট্রাভার্সাল শিডিউল করে।
এর ফলে, UI ফ্রিজ হয়ে যায়। যেহেতু MessageQueue লিকেজ হওয়া ব্যারিয়ারের পরে কোনও
সিনক্রোনাস মেসেজ প্রসেস করতে পারে না, তাই মূল থ্রেডটি একটি নিষ্ক্রিয়
অবস্থায় প্রবেশ করে। এই সমস্যাটি সাধারণত ANR হিসেবে দেখা দেয় এবং nativePollOnce স্ট্যাক ট্রেসে
থাকে।
ভিউ থ্রেডিং লঙ্ঘন এড়াতে, এইসব পেশাদার পদ্ধতি অনুসরণ করুন:
lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { val data = myRepository.getData() withContext(Dispatchers.Main) { // Switch context to Main myTextView.text = data.title } }
পেশাদার পদ্ধতি অনুসরণ করতে আপনাকে সাহায্য করার জন্য, Android অন্যান্য থ্রেড থেকে UI থ্রেড অ্যাক্সেস করার বিভিন্ন উপায় অফার করে:
জনপ্রিয় ইমেজ লোডার, রিঅ্যাক্টিভ এক্সটেনশন ফ্রেমওয়ার্ক, ইভেন্ট বাস লাইব্রেরি এবং অন্যান্য থ্রেডিং সলিউশন সাধারণত মূল থ্রেডে নির্দিষ্ট ইভেন্ট পর্যবেক্ষণ করার উপায় অফার করে। এটি সেইসব পর্যবেক্ষক ও ইভেন্ট লিসনারদের জন্য উপযোগী যাদের ভিউয়ের স্টেট পেতে ও সেট করতে হয়।
কীভাবে ডিবাগ করবেন
Android 17-এ ডেভেলপমেন্টের সময় ভিউ থ্রেডিং সংক্রান্ত লঙ্ঘন শনাক্ত, ট্রেস ও সমাধান করতে সাহায্য করার জন্য নতুন টুল দেওয়া হয়েছে।
১. কম্প্যাটিবিলিটি ফ্রেমওয়ার্ক টুল
মানানসই ফ্রেমওয়ার্ক টুল, অ্যাপ ডেভেলপারদের ডেভেলপার বিকল্প বা ADB ব্যবহার করে আলাদা আলাদাভাবে আচরণগত পরিবর্তন চালু ও বন্ধ করতে দেয়। আপনি নিম্নলিখিত ধাপগুলি ব্যবহার করে ভিউ টগল করতে থ্রেডিং লঙ্ঘন সংক্রান্ত আচরণগত পরিবর্তন করতে পারবেন:
এছাড়াও, আপনি ADB ব্যবহার করে ফ্ল্যাগ টগল করে চালু বা বন্ধ করতে পারবেন:
$ 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>
এই ফ্ল্যাগ চালু করলে, ভুল থ্রেড থেকে কোনও View API কল করা হলে, অ্যাপটি একটি ব্যতিক্রম ছুঁড়ে ফেলে এবং ক্র্যাশ করে। এটি আপনাকে ভিউ থ্রেডিং লঙ্ঘন সংক্রান্ত সমস্যা ধরতে এবং সমাধান করতে সাহায্য করে।
২. CalledFromWrongThreadListener API
এছাড়াও, আপনি গ্লোবাল
View#registerCalledFromWrongThreadListener API প্রয়োগ করে প্রোগ্র্যামাটিক উপায়ে অনুপযুক্ত থ্রেড
অ্যাক্সেস শনাক্ত করতে পারেন।
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 স্ট্যাকে "nativePollOnce" বা "message queue idle" ফ্রেম দেখতে পেলে, এটি প্রায়ই ইঙ্গিত করে যে সন্দেহজনক উত্তর না দেওয়া থ্রেডটি আসলে আইডল ছিল এবং লুপার মেসেজের জন্য অপেক্ষা করছিল। Google Play Console-এ, ANR সংক্রান্ত বিবরণটি এই রকম দেখায়:
Native method - android.os.MessageQueue.nativePollOnce
Executing service com.example.app/com.example.app.MyService
যেমন, মূল থ্রেড অলস থাকলে স্ট্যাকগুলি এইরকম দেখাবে:
"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)
সন্দেহজনকভাবে উত্তর না দেওয়া থ্রেড অলস থাকার একাধিক কারণ থাকতে পারে:
"nativePollOnce" ANR-এর অন্তর্নিহিত ট্রিগার ANR-এর ধরন অনুযায়ী আলাদা আলাদা হয় বলে, নির্দিষ্ট ANR বিভাগ নির্ণয় করলে, আপনার অ্যাপের মধ্যে সমস্যা সমাধানের জন্য অ্যাকশনযোগ্য ধাপগুলি শনাক্ত করতে সাহায্য করতে পারে।
| বিভাগ | কারণ | সাজেস্ট করা সমাধান |
|---|---|---|
| ইনপুট ডিসপ্যাচ করার সময়সীমা পেরিয়ে গেছে | সিস্টেম-ব্যাপী সমস্যা লেট স্ট্যাক ডাম্প |
কিছু করার প্রয়োজন নেই। |
| কোনও ফোকাস করা উইন্ডো নেই | সিস্টেম-ব্যাপী সমস্যা লেট স্ট্যাক ডাম্প থ্রেডিং লঙ্ঘন দেখুন |
ভিউ থ্রেডিং সংক্রান্ত নীতি লঙ্ঘন হয়েছে কিনা তা কোডবেস চেক করে দেখুন। |
| ব্রডকাস্ট রিসিভার টাইম-আউট | দেরিতে স্ট্যাক ডাম্প সিস্টেম-ব্যাপী সমস্যা থ্রেড ভুল অ্যাট্রিবিউশন থ্রেডিং লঙ্ঘন দেখুন |
স্ট্যাক ডাম্পে প্রাসঙ্গিক থ্রেডগুলি পরীক্ষা করুন। ভিউ থ্রেডিং সংক্রান্ত লঙ্ঘনের জন্য কোডবেস চেক করুন। |
| এক্সিকিউট করার সময় পরিষেবা টাইম-আউট হয়ে গেছে | দেরিতে স্ট্যাক ডাম্প সিস্টেম-ব্যাপী সমস্যা থ্রেডিং লঙ্ঘন দেখুন |
ভিউ থ্রেডিং সংক্রান্ত নীতি লঙ্ঘন হয়েছে কিনা তা কোডবেস চেক করে দেখুন। |
| কন্টেন্ট প্রদানকারী উত্তর দিচ্ছেন না | দেরিতে স্ট্যাক ডাম্প সিস্টেম-ব্যাপী সমস্যা থ্রেড মিসঅ্যাট্রিবিউশন |
স্ট্যাক ডাম্পে প্রাসঙ্গিক থ্রেডগুলি পরীক্ষা করুন। |
nativePollOnce ANR বিশ্লেষণ করার জন্য সাজেস্ট করা ধাপগুলি এখানে দেওয়া হল।
কোনও স্ট্যাক ফ্রেম নেই
কিছু ANR রিপোর্টে ANR সহ স্ট্যাক অন্তর্ভুক্ত থাকে না, এর অর্থ হল ANR রিপোর্ট তৈরি করার সময় স্ট্যাক ডাম্পিং কাজ করেনি। স্ট্যাক ফ্রেম মিসিং হওয়ার সম্ভাব্য কারণগুলি হল:
[...]
--- 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 -----
[...]
স্ট্যাক ফ্রেম না থাকা ANR-এর ক্ষেত্রে ক্লাস্টার সিগনেচার বা ANR রিপোর্ট থেকে কোনও অ্যাকশন নেওয়া যায় না। ডিবাগ করতে, অ্যাপের জন্য অন্যান্য ক্লাস্টার দেখুন, কারণ কোনও সমস্যা যথেষ্ট বড় হলে সাধারণত সেটির নিজস্ব ক্লাস্টার থাকে যেখানে স্ট্যাক ফ্রেম উপস্থিত থাকে। অন্য একটি বিকল্প হল Perfetto ট্রেস দেখা।
পরিচিত সমস্যা
আপনার অ্যাপের প্রসেসে টাইমার রেখে ANR ট্রিগার হওয়ার আগে ব্রডকাস্ট হ্যান্ডেলিং শেষ করার চেষ্টা করলে তা সঠিকভাবে কাজ নাও করতে পারে, কারণ সিস্টেম অ্যাসিঙ্ক্রোনাস পদ্ধতিতে ANR মনিটর করে।