ANR নির্ণয় করুন এবং ঠিক করুন

যখন একটি অ্যান্ড্রয়েড অ্যাপের UI থ্রেড খুব দীর্ঘ সময়ের জন্য অবরুদ্ধ থাকে, তখন সিস্টেমটি একটি "অ্যাপ্লিকেশন নট রেসপন্ডিং" (ANR) ত্রুটি পাঠায়৷ এই পৃষ্ঠাটি বিভিন্ন ধরণের ANR, কীভাবে সেগুলি নির্ণয় করতে হয় এবং সেগুলি ঠিক করার পরামর্শগুলি বর্ণনা করে৷ তালিকাভুক্ত সমস্ত ডিফল্ট সময়সীমার সময়সীমা AOSP এবং Pixel ডিভাইসের জন্য; এই সময় OEM দ্বারা পরিবর্তিত হতে পারে.

মনে রাখবেন যে ANR-এর কারণ নির্ধারণ করার সময়, সিস্টেম এবং অ্যাপের সমস্যাগুলির মধ্যে পার্থক্য করা সহায়ক।

যখন সিস্টেমটি খারাপ অবস্থায় থাকে, তখন নিম্নলিখিত সমস্যাগুলি ANR সৃষ্টি করতে পারে:

  • সিস্টেম সার্ভারে ক্ষণস্থায়ী সমস্যার কারণে সাধারণত দ্রুত বাইন্ডার কল ধীর হয়।
  • সিস্টেম সার্ভারের সমস্যা এবং উচ্চ ডিভাইস লোডের কারণে অ্যাপ থ্রেড নির্ধারিত হয় না।

আপনার কাছে উপলব্ধ হলে, সিস্টেম এবং অ্যাপ সমস্যাগুলির মধ্যে পার্থক্য করার একটি ভাল উপায় হল Perfetto ট্রেস ব্যবহার করা:

  • অ্যাপটির মূল থ্রেডটি চলছে কিনা তা দেখার জন্য পারফেটোতে থ্রেড স্টেট ট্র্যাক দেখে নির্ধারিত হয়েছে কিনা তা দেখুন।
  • লক কন্টেন্টের মতো সমস্যাগুলির জন্য system_server থ্রেডগুলি দেখুন।
  • ধীরগতির বাইন্ডার কলের জন্য, উত্তর থ্রেডটি দেখুন, যদি উপস্থিত থাকে, কেন এটি ধীর তা দেখতে।

ইনপুট প্রেরণের সময়সীমা

ইনপুট ডিসপ্যাচ ANRগুলি ঘটে যখন অ্যাপের প্রধান থ্রেড কোনো ইনপুট ইভেন্টে সাড়া না দেয়, যেমন একটি সোয়াইপ বা কী প্রেস করার সময়। যেহেতু অ্যাপটি ফোরগ্রাউন্ডে থাকে যখন ইনপুট ডিসপ্যাচ টাইমআউট ঘটে, সেগুলি প্রায় সবসময় ব্যবহারকারীর কাছে দৃশ্যমান এবং প্রশমিত করা খুবই গুরুত্বপূর্ণ৷

ডিফল্ট সময়সীমা : 5 সেকেন্ড।

ইনপুট প্রেরণ ANR সাধারণত প্রধান থ্রেডের সমস্যার কারণে হয়। যদি মূল থ্রেডটি একটি লক পাওয়ার অপেক্ষায় অবরুদ্ধ থাকে, তাহলে হোল্ডার থ্রেডটিও জড়িত হতে পারে।

ইনপুট প্রেরণ ANR এড়াতে, এই সেরা অনুশীলনগুলি অনুসরণ করুন:

  • প্রধান থ্রেডে ব্লকিং বা দীর্ঘ-চলমান ক্রিয়াকলাপগুলি সঞ্চালন করবেন না। প্রধান থ্রেডে দুর্ঘটনাজনিত কার্যকলাপ ধরতে StrictMode ব্যবহার করার কথা বিবেচনা করুন।
  • প্রধান থ্রেড এবং অন্যান্য থ্রেডের মধ্যে লক বিরোধ কমিয়ে দিন।
  • প্রধান থ্রেডে নন-ইউআই কাজ কমিয়ে দিন, যেমন সম্প্রচার পরিচালনা বা পরিষেবা চালানোর সময়।

সাধারণ কারণ

ইনপুট প্রেরণ ANR-এর জন্য এখানে কিছু সাধারণ কারণ এবং প্রস্তাবিত সমাধান রয়েছে৷

কারণ কি ঘটেছে প্রস্তাবিত সংশোধন
ধীর বাইন্ডার কল প্রধান থ্রেড একটি দীর্ঘ সিঙ্ক্রোনাস বাইন্ডার কল করে। কলটি মূল থ্রেড থেকে সরান বা কলটি অপ্টিমাইজ করার চেষ্টা করুন, যদি আপনি API এর মালিক হন।
পরপর অনেক বাইন্ডার কল প্রধান থ্রেড অনেকগুলো পরপর সিঙ্ক্রোনাস বাইন্ডার কল করে। আঁটসাঁট লুপে বাইন্ডার কল করবেন না।
I/O ব্লক করা হচ্ছে প্রধান থ্রেড I/O কল ব্লক করে, যেমন ডাটাবেস বা নেটওয়ার্ক অ্যাক্সেস। সমস্ত ব্লকিং IO প্রধান থ্রেড থেকে সরান।
লক বিরোধ একটি লক পাওয়ার অপেক্ষায় প্রধান থ্রেড অবরুদ্ধ। প্রধান থ্রেড এবং অন্যান্য থ্রেড মধ্যে লক বিরোধ কমাতে. অন্য থ্রেডে ধীর কোড অপ্টিমাইজ করুন।
ব্যয়বহুল ফ্রেম একটি একক ফ্রেমে অত্যধিক রেন্ডারিং, গুরুতর জ্যাঙ্ক সৃষ্টি করে৷ ফ্রেম রেন্ডিং কম কাজ করুন. n 2 অ্যালগরিদম ব্যবহার করবেন না। স্ক্রলিং বা পেজিং-এর মতো জিনিসের জন্য দক্ষ উপাদান ব্যবহার করুন—উদাহরণস্বরূপ, জেটপ্যাক পেজিং লাইব্রেরি
অন্যান্য উপাদান দ্বারা অবরুদ্ধ একটি ভিন্ন উপাদান, যেমন একটি সম্প্রচার রিসিভার, চলমান এবং মূল থ্রেড ব্লক করে। যতটা সম্ভব মূল থ্রেড থেকে অ-ইউআই কাজ সরান। একটি ভিন্ন থ্রেডে সম্প্রচার রিসিভার চালান।
জিপিইউ হ্যাং GPU হ্যাং একটি সিস্টেম বা হার্ডওয়্যার সমস্যা যা রেন্ডারিংকে ব্লক করে দেয় এবং তাই একটি ইনপুট ডিসপ্যাচ ANR। দুর্ভাগ্যবশত, সাধারণত অ্যাপের দিকে কোনো সংশোধন করা হয় না। যদি সম্ভব হয়, সমস্যা সমাধানের জন্য হার্ডওয়্যার টিমের সাথে যোগাযোগ করুন।

কিভাবে ডিবাগ করতে হয়

Google Play Console বা Firebase Crashlytics- এ ANR ক্লাস্টার স্বাক্ষর দেখে ডিবাগিং শুরু করুন। ক্লাস্টারে সাধারণত উপরের ফ্রেমগুলি থাকে যা ANR ঘটাতে পারে বলে সন্দেহ করা হয়।

নিম্নলিখিত ফ্লো চার্ট দেখায় কিভাবে একটি ইনপুট টাইমআউট ডিসপ্যাচ ANR এর কারণ নির্ধারণ করতে হয়।

চিত্র 1. কিভাবে একটি ইনপুট ডিসপ্যাচ ANR ডিবাগ করবেন।

প্লে ভাইটালগুলি এই সাধারণ ANR কারণগুলির মধ্যে কিছু সনাক্ত করতে এবং ডিবাগ করতে সাহায্য করতে পারে। উদাহরণ স্বরূপ, যদি ভাইটাল শনাক্ত করে যে লক কন্টেন্টের কারণে একটি ANR ঘটেছে, তাহলে এটি সমস্যাটির সংক্ষিপ্ত বিবরণ দিতে পারে এবং ANR ইনসাইটস বিভাগে সমাধানের সুপারিশ করতে পারে।

চিত্র 2. প্লে ভাইটাল ANR সনাক্তকরণ।

কোন ফোকাস করা উইন্ডো নেই

স্পর্শের মতো ইভেন্টগুলি সরাসরি হিট টেস্টিং-এর উপর ভিত্তি করে প্রাসঙ্গিক উইন্ডোতে পাঠানো হলে, কীগুলির মতো ইভেন্টগুলির একটি লক্ষ্য প্রয়োজন। এই টার্গেটকে ফোকাস করা উইন্ডো বলা হয়। প্রতি ডিসপ্লেতে শুধুমাত্র একটি ফোকাস করা উইন্ডো আছে এবং এটি সাধারণত সেই উইন্ডো যেটির সাথে ব্যবহারকারী বর্তমানে ইন্টারঅ্যাক্ট করছেন। যদি একটি ফোকাস করা উইন্ডো খুঁজে না পাওয়া যায়, ইনপুট একটি নো-ফোকাসড-উইন্ডো ANR উত্থাপন করে। একটি নো-ফোকাসড-উইন্ডো ANR হল এক প্রকার ইনপুট ডিসপ্যাচ ANR।

ডিফল্ট সময়সীমা : 5 সেকেন্ড।

সাধারণ কারণ

নো-ফোকাসড-উইন্ডো ANR সাধারণত নিম্নলিখিত সমস্যার যে কোনো একটির কারণে হয়:

  • অ্যাপটি খুব বেশি কাজ করছে এবং প্রথম ফ্রেমটি আঁকতে খুব ধীর।
  • প্রধান উইন্ডো ফোকাসযোগ্য নয়. যদি একটি উইন্ডো FLAG_NOT_FOCUSABLE দিয়ে ফ্ল্যাগ করা হয়, ব্যবহারকারী এতে কী বা বোতাম ইভেন্ট পাঠাতে পারবেন না।

কোটলিন

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 ঘটে যখন একটি ব্রডকাস্ট রিসিভার সময়মতো একটি সম্প্রচার পরিচালনা করে না। সিঙ্ক্রোনাস রিসিভার, বা রিসিভার যারা goAync() কল করে না, একটি টাইমআউট মানে onReceive() সময়ে সম্পূর্ণ হয়নি। অ্যাসিঙ্ক রিসিভার বা রিসিভারদের জন্য যারা goAsync() কল করে, একটি টাইমআউট মানে PendingResult.finish() সময়মতো কল করা হয়নি।

ব্রডকাস্ট রিসিভার ANR প্রায়ই এই থ্রেডগুলিতে ঘটে:

  • মূল থ্রেড, যদি সমস্যাটি ধীর অ্যাপ স্টার্টআপ হয়।
  • থ্রেড চলমান সম্প্রচার রিসিভার, যদি সমস্যাটি ধীর হয় onReceive() কোড।
  • ব্রডকাস্ট কর্মী থ্রেড, যদি সমস্যাটি ধীরগতির হয় goAsync() ব্রডকাস্ট কোড।

ব্রডকাস্ট রিসিভার ANR এড়াতে, এই সেরা অনুশীলনগুলি অনুসরণ করুন:

  • নিশ্চিত করুন যে অ্যাপ স্টার্টআপ দ্রুত হয়, যেহেতু অ্যাপটি সম্প্রচার পরিচালনা করতে শুরু করলে এটি ANR টাইমআউটে গণনা করা হয়।
  • goAsync() ব্যবহার করা হলে, নিশ্চিত করুন যে PendingResult.finish() দ্রুত কল করা হয়েছে। এটি সিঙ্ক্রোনাস ব্রডকাস্ট রিসিভারের মতো একই ANR সময়সীমার সাপেক্ষে।
  • যদি goAsync() ব্যবহার করা হয়, নিশ্চিত করুন যে কর্মী থ্রেড(গুলি) অন্যান্য দীর্ঘ-চলমান বা ব্লকিং ক্রিয়াকলাপগুলির সাথে ভাগ করা হয়নি৷
  • মূল থ্রেডে চলমান UI কোড ব্লক করা এড়াতে একটি নন-মেইন থ্রেডে সম্প্রচার রিসিভার চালানোর জন্য registerReceiver() ব্যবহার করার কথা বিবেচনা করুন।

সময়সীমা

সম্প্রচার প্রাপ্তির সময়সীমার অগ্রভাগের অভিপ্রায় পতাকা সেট করা আছে কিনা এবং প্ল্যাটফর্ম সংস্করণের উপর নির্ভর করে।

অভিপ্রায় প্রকার অ্যান্ড্রয়েড 13 এবং তার নিচের Android 14 এবং উচ্চতর

ফোরগ্রাউন্ড অগ্রাধিকার অভিপ্রায়

( FLAG_RECEIVER_FOREGROUND সেট)

10 সেকেন্ড

10-20 সেকেন্ড, প্রক্রিয়া CPU-অনাহারে কিনা তার উপর নির্ভর করে

পটভূমি অগ্রাধিকার অভিপ্রায়

( FLAG_RECEIVER_FOREGROUND সেট করা হয়নি)

60 সেকেন্ড

60-120 সেকেন্ড, প্রক্রিয়া সিপিইউ-ক্ষুধার্ত কিনা তার উপর নির্ভর করে

FLAG_RECEIVER_FOREGROUND পতাকা সেট করা আছে কিনা তা জানাতে, ANR বিষয়ের মধ্যে "flg=" সন্ধান করুন এবং 0x10000000 এর উপস্থিতি পরীক্ষা করুন৷ যদি এই বিটটি সেট করা থাকে, তাহলে অভিপ্রায়টি FLAG_RECEIVER_FOREGROUND সেট করা থাকে এবং তাই সময়সীমা কম হয়৷

সংক্ষিপ্ত সম্প্রচারের সময়সীমা সহ ANR বিষয়ের উদাহরণ (10-20 সেকেন্ড):

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

দীর্ঘ সম্প্রচারের সময়সীমা সহ ANR বিষয়ের উদাহরণ (60-120 সেকেন্ড):

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

সম্প্রচারের সময় কিভাবে পরিমাপ করা হয়

সম্প্রচারের সময়কাল পরিমাপ শুরু হয় যখন সম্প্রচারটি system_server থেকে অ্যাপে পাঠানো হয়, এবং অ্যাপটি সম্প্রচার প্রক্রিয়া করা শেষ হলে শেষ হয়। যদি অ্যাপ প্রক্রিয়াটি ইতিমধ্যেই চলমান না থাকে, তাহলে এটিকে ANR সময়সীমার মধ্যে একটি ঠান্ডা শুরু করতে হবে। তাই, ধীরগতির অ্যাপ স্টার্টআপের ফলে ব্রডকাস্ট রিসিভার ANR হতে পারে।

নিচের চিত্রটি ব্রডকাস্ট রিসিভার ANR টাইমলাইনকে নির্দিষ্ট অ্যাপ প্রক্রিয়ার সাথে সারিবদ্ধ করে।

চিত্র 3. ব্রডকাস্ট রিসিভার ANR টাইমলাইন।

ANR টাইমআউট পরিমাপ শেষ হয় যখন রিসিভার সম্প্রচার প্রক্রিয়া শেষ করে: ঠিক কখন এটি ঘটে তা নির্ভর করে এটি একটি সিঙ্ক্রোনাস নাকি অ্যাসিঙ্ক্রোনাস রিসিভার।

  • সিঙ্ক্রোনাস রিসিভারের জন্য, onReceive() রিটার্ন করলে পরিমাপ বন্ধ হয়ে যায়।
  • অ্যাসিঙ্ক্রোনাস রিসিভারের জন্য, যখন PendingResult.finish() বলা হয় তখন পরিমাপ বন্ধ হয়ে যায়।
চিত্র 4. সিঙ্ক্রোনাস এবং অ্যাসিঙ্ক্রোনাস রিসিভারের জন্য ANR টাইমআউট পরিমাপের শেষ পয়েন্ট।

সাধারণ কারণ

ব্রডকাস্ট রিসিভার ANR-এর জন্য এখানে কিছু সাধারণ কারণ এবং প্রস্তাবিত সমাধান দেওয়া হল।

কারণ প্রযোজ্য কি হলো প্রস্তাবিত ফিক্স
স্লো অ্যাপ স্টার্টআপ সমস্ত রিসিভার অ্যাপটি কোল্ড স্টার্ট করতে খুব বেশি সময় নিয়েছে। মন্থর অ্যাপ্লিকেশন শুরু অপ্টিমাইজ করুন.
onReceive() নির্ধারিত নয় সমস্ত রিসিভার ব্রডকাস্ট রিসিভার থ্রেড অন্য কাজে ব্যস্ত ছিল এবং onReceive() পদ্ধতি শুরু করতে পারেনি। রিসিভার থ্রেডে দীর্ঘ-চলমান কাজগুলি করবেন না (বা রিসিভারকে ডেডিকেটেড থ্রেডে নিয়ে যান)।
স্লো onReceive() সমস্ত রিসিভার, কিন্তু প্রধানত সিঙ্ক্রোনাস বেশী onReceive() পদ্ধতিটি শুরু হয়েছিল কিন্তু অবরুদ্ধ বা ধীর ছিল তাই সময়মতো সম্পূর্ণ হয়নি। ধীর রিসিভার কোড অপ্টিমাইজ করুন.
অ্যাসিঙ্ক রিসিভারের কাজগুলি নির্ধারিত নেই৷ goAsync() রিসিভার onReceive() পদ্ধতিটি একটি অবরুদ্ধ কর্মী থ্রেড পুলে কাজ চালানোর চেষ্টা করেছে, তাই কাজটি কখনই শুরু হয়নি। ধীরগতির বা ব্লকিং কল অপ্টিমাইজ করুন বা সম্প্রচার কর্মীদের বনাম অন্যান্য দীর্ঘ-চলমান কাজের জন্য বিভিন্ন থ্রেড ব্যবহার করুন।
কর্মীরা ধীর বা অবরুদ্ধ goAsync() রিসিভার সম্প্রচার প্রক্রিয়া করার সময় কর্মী থ্রেড পুলের কোথাও একটি ব্লকিং বা ধীর অপারেশন ছিল। তাই, PendingResult.finish সময়মতো কল করা হয়নি। ধীর async রিসিভার কোড অপ্টিমাইজ করুন।
PendingResult.finish কল করতে ভুলে গেছি goAsync() রিসিভার Call to finish() কোড পাথ থেকে অনুপস্থিত। নিশ্চিত করুন finish() সবসময় কল করা হয়।

কিভাবে ডিবাগ করতে হয়

ক্লাস্টার স্বাক্ষর এবং ANR রিপোর্টের উপর ভিত্তি করে, আপনি যে থ্রেডটি রিসিভার চালাচ্ছেন সেটি সনাক্ত করতে পারেন এবং তারপর নির্দিষ্ট কোডটি অনুপস্থিত বা ধীরে ধীরে চলছে।

নিম্নলিখিত ফ্লো চার্ট দেখায় কিভাবে একটি সম্প্রচার রিসিভার ANR এর কারণ নির্ধারণ করতে হয়।

চিত্র 5. কিভাবে একটি সম্প্রচার রিসিভার 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 থ্রেড [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 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)
    

    আপনি যদি কোনও গুরুত্বপূর্ণ ফাংশন কল দেখতে না পান তবে আরও কয়েকটি সম্ভাবনা রয়েছে:

    • পরিষেবাটি চলছে বা বন্ধ হচ্ছে, যার মানে স্ট্যাকগুলি খুব দেরিতে নেওয়া হয়েছে৷ এই ক্ষেত্রে, আপনি একটি মিথ্যা পজিটিভ হিসাবে ANR উপেক্ষা করতে পারেন।
    • একটি ভিন্ন অ্যাপ কম্পোনেন্ট চলছে, যেমন একটি ব্রডকাস্ট রিসিভার। এই ক্ষেত্রে প্রধান থ্রেড সম্ভবত এই উপাদানটিতে ব্লক করা হয়েছে, পরিষেবাটি শুরু হতে বাধা দিচ্ছে।
  3. আপনি যদি একটি মূল ফাংশন কল দেখতে পান এবং ANR সাধারণত কোথায় ঘটছে তা নির্ধারণ করতে পারেন, তবে ধীর অপারেশনটি খুঁজে পেতে এবং এটিকে অপ্টিমাইজ করতে বা এটিকে জটিল পথ থেকে সরাতে বাকি মূল থ্রেড স্ট্যাকগুলি পরীক্ষা করুন৷

পরিষেবা সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত পৃষ্ঠাগুলি দেখুন:

কন্টেন্ট প্রদানকারী সাড়া দিচ্ছে না

একটি বিষয়বস্তু প্রদানকারী ANR ঘটে যখন একটি দূরবর্তী সামগ্রী প্রদানকারী একটি প্রশ্নের উত্তর দিতে সময়সীমার চেয়ে বেশি সময় নেয় এবং তাকে হত্যা করা হয়।

ডিফল্ট টাইমআউট পিরিয়ড : ContentProviderClient.setDetectNotResponding ব্যবহার করে বিষয়বস্তু প্রদানকারী দ্বারা নির্দিষ্ট করা হয়েছে। ANR টাইমআউট পিরিয়ডে রিমোট কন্টেন্ট প্রোভাইডার ক্যোয়ারী চালানোর জন্য মোট সময় অন্তর্ভুক্ত থাকে, যার মধ্যে রিমোট অ্যাপটি আগে থেকে চালু না থাকলে ঠান্ডা শুরু করা অন্তর্ভুক্ত থাকে।

বিষয়বস্তু প্রদানকারীর ANR এড়াতে, এই সেরা অনুশীলনগুলি অনুসরণ করুন:

  • নিশ্চিত করুন যে অ্যাপ স্টার্টআপ দ্রুত হয়, যেহেতু এটি ANR টাইমআউটে গণনা করা হয় যদি অ্যাপটি সামগ্রী প্রদানকারী চালানোর জন্য শুরু করা হয়।
  • নিশ্চিত করুন যে বিষয়বস্তু প্রদানকারীর প্রশ্ন দ্রুত হয়।
  • অনেক সমসাময়িক ব্লকিং বাইন্ডার কল করবেন না যা অ্যাপের সমস্ত বাইন্ডার থ্রেড ব্লক করতে পারে।

সাধারণ কারণ

নিম্নলিখিত সারণীতে বিষয়বস্তু প্রদানকারীর ANR-এর সাধারণ কারণ এবং প্রস্তাবিত সমাধানের তালিকা রয়েছে।

কারণ কি ঘটেছে সংকেত প্রস্তাবিত ফিক্স
ধীর বিষয়বস্তু প্রদানকারী ক্যোয়ারী বিষয়বস্তু প্রদানকারী কার্যকর করতে খুব বেশি সময় নেয় বা ব্লক করা হয়। android.content.ContentProvider$Transport.query ফ্রেমটি বাইন্ডার থ্রেডে রয়েছে। কন্টেন্ট প্রদানকারীর ক্যোয়ারী অপ্টিমাইজ করুন। বাইন্ডার থ্রেডকে কী ব্লক করছে তা খুঁজে বের করুন।
স্লো অ্যাপ স্টার্টআপ কন্টেন্ট প্রদানকারীর অ্যাপটি শুরু হতে খুব বেশি সময় নেয়। ActivityThread.handleBindApplication ফ্রেম প্রধান থ্রেডে রয়েছে। অ্যাপ স্টার্টআপ অপ্টিমাইজ করুন।
বাইন্ডার থ্রেড ক্লান্তি - সমস্ত বাইন্ডার থ্রেড ব্যস্ত সমস্ত বাইন্ডার থ্রেড অন্যান্য সিঙ্ক্রোনাস অনুরোধগুলি পরিবেশন করতে ব্যস্ত তাই সামগ্রী প্রদানকারী বাইন্ডার কলটি চলতে পারে না৷ অ্যাপটি শুরু হচ্ছে না, সমস্ত বাইন্ডার থ্রেড ব্যস্ত, এবং সামগ্রী প্রদানকারী চলছে না। বাইন্ডার থ্রেডের লোড হ্রাস করুন। অর্থাৎ, কম সিঙ্ক্রোনাস আউটগোয়িং বাইন্ডার কল করুন বা ইনকামিং কলগুলি পরিচালনা করার সময় কম কাজ করুন।

কিভাবে ডিবাগ করতে হয়

Google Play Console বা Firebase Crashlytics-এ ক্লাস্টার স্বাক্ষর এবং ANR রিপোর্ট ব্যবহার করে একটি সামগ্রী প্রদানকারী ANR ডিবাগ করতে, প্রধান থ্রেড এবং বাইন্ডার থ্রেড(গুলি) কী করছে তা দেখুন।

নিম্নলিখিত ফ্লো চার্ট বর্ণনা করে কিভাবে একটি বিষয়বস্তু প্রদানকারী ANR ডিবাগ করতে হয়:

চিত্র 7. কিভাবে একটি বিষয়বস্তু প্রদানকারী 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)

কাজের মন্থর প্রতিক্রিয়া

অ্যাপ্লিকেশানটি JobService.onStartJob() বা JobService.onStopJob() এ প্রতিক্রিয়া জানাতে খুব বেশি সময় নেয় বা JobService.setNotification() ব্যবহার করে একটি বিজ্ঞপ্তি প্রদান করতে খুব বেশি সময় নেয় তখন একটি ধীর কাজের প্রতিক্রিয়া ANR হয়৷ এটি পরামর্শ দেয় যে অ্যাপের মূল থ্রেডটি অন্য কিছু করার জন্য ব্লক করা হয়েছে।

JobService.onStartJob() বা JobService.onStopJob() এর সাথে সমস্যা হলে, মূল থ্রেডে কী ঘটছে তা পরীক্ষা করুন। JobService.setNotification() এর সাথে সমস্যা হলে, যত তাড়াতাড়ি সম্ভব কল করতে ভুলবেন না। বিজ্ঞপ্তি দেওয়ার আগে অনেক কাজ করবেন না।

রহস্য ANR

কখনও কখনও এটি অস্পষ্ট হয় কেন একটি ANR ঘটছে, বা ক্লাস্টার স্বাক্ষর এবং ANR রিপোর্টে এটি ডিবাগ করার জন্য অপর্যাপ্ত তথ্য রয়েছে। এই ক্ষেত্রে, ANR কার্যকর কিনা তা নির্ধারণ করতে আপনি এখনও কিছু পদক্ষেপ নিতে পারেন।

বার্তা সারি নিষ্ক্রিয় বা নেটিভপোলঅনসে

আপনি যদি স্ট্যাকের মধ্যে android.os.MessageQueue.nativePollOnce ফ্রেমটি দেখতে পান, তবে এটি প্রায়শই ইঙ্গিত দেয় যে সন্দেহজনক প্রতিক্রিয়াহীন থ্রেডটি আসলে নিষ্ক্রিয় ছিল এবং লুপার বার্তাগুলির জন্য অপেক্ষা করছে৷ 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)

সন্দেহজনক প্রতিক্রিয়াশীল থ্রেড নিষ্ক্রিয় হতে পারে এমন বিভিন্ন কারণ রয়েছে:

  • দেরী স্ট্যাক ডাম্প . ANR ট্রিগারিং এবং স্ট্যাকগুলি ডাম্প করার মধ্যে অল্প সময়ের মধ্যে থ্রেডটি উদ্ধার করা হয়েছে। Android 13-এ Pixels-এ লেটেন্সি প্রায় 100ms, কিন্তু 1s ছাড়িয়ে যেতে পারে। Android 14-এ Pixels-এ লেটেন্সি সাধারণত 10ms এর কম হয়।
  • থ্রেড ভুল বন্টন . ANR স্বাক্ষর তৈরি করতে ব্যবহৃত থ্রেডটি প্রকৃত অপ্রতিক্রিয়াশীল থ্রেড ছিল না যা ANR সৃষ্টি করেছিল। এই ক্ষেত্রে, 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গুলিকে অ্যাসিঙ্ক্রোনাস উপায়ে নিরীক্ষণ করে।