عیب‌یابی سرویس‌های پیش‌زمینه‌ای

این صفحه برخی‌از دلایل رایج ناموفق بودن سرویس‌های پیش‌زمینه‌ای را شرح می‌دهد و به شما کمک می‌کند علت مشکل را شناسایی کنید.

این سند به مشکلات زیر می‌پردازد:

قبل‌از عیب‌یابی کردن

بررسی تغییرات اخیر در سرویس‌های پیش‌زمینه‌ای

اگر از سرویس‌های پیش‌زمینه‌ای به‌درستی استفاده نشود، می‌توانند تأثیرات منفی بر عملکرد دستگاه و عمر باتری داشته باشند. به همین دلیل، نسخه‌های پلاتفرم Android اغلب تغییراتی در رفتار سرویس پیش‌زمینه‌ای ایجاد می‌کنند تا این تأثیرات بد را محدود کنند.

اگر با سرویس‌های پیش‌زمینه‌ای مشکل دارید، باید سند تغییرات سرویس‌های پیش‌زمینه‌ای را بررسی کنید و ببینید آیا تغییرات اخیر می‌تواند مشکلات شما را توضیح دهد. به‌ویژه در شرایط زیر، بررسی تغییرات بسیار مهم است:

  • کد سرویس پیش‌زمینه‌ای که قبلاً کار می‌کرد اکنون ناموفق است
  • به‌تازگی آزمایش را در نسخه پلاتفرم جدیدی شروع کرده‌اید، یا سطح میانای برنامه‌سازی کاربردی هدف برنامه‌تان را تغییر داده‌اید

علاوه‌براین، اگر دستگاهتان را در پیش‌نمای توسعه‌دهندگان نرم‌افزار پلاتفرم آزمایش می‌کنید، حتماً جدیدترین نسخه اسناد پیش‌نمای توسعه‌دهندگان نرم‌افزار را بررسی کنید.

خطاهای «برنامه پاسخ نمی‌دهد» (ANR)

در شرایط خاصی، انتظار می‌رود برنامه سرویس پیش‌زمینه‌ای خود را خاموش کند. اگر برنامه سرویس را متوقف نکند، سیستم سرویس را متوقف می‌کند و خطای برنامه پاسخ نمی‌دهد (ANR) را راه‌اندازی می‌کند.

سرویس کوتاه مدت زیادی اجرا می‌شود و خطای ANR ایجاد می‌کند

سرویس‌های پیش‌زمینه‌ای که از نوع سرویس کوتاه استفاده می‌کنند باید سریعاً، ظرف حدود سه دقیقه، تکمیل شوند. وقتی زمان تمام می‌شود، سیستم روش Service.onTimeout(int,int) سرویس را فراخوانی می‌کند. این سرویس چند ثانیه فرصت دارد تا با stopSelf() تماس بگیرد. اگر سرویس خودش متوقف نشود، سیستم خطای «برنامه پاسخ نمی‌دهد» را راه‌اندازی می‌کند.

عیب‌یابی:

اگر خطای ANR به‌دلیل توقف ناموفق سرویس پیش‌زمینه‌ای ایجاد شده باشد، سیستم یک استثنای داخلی ایجاد می‌کند. با بررسی گزارش‌های ANR می‌توانید تأیید کنید که مشکل همین بوده است. اگر مشکل این باشد، گزارش حاوی پیام زیر خواهد بود:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type FOREGROUND_SERVICE_TYPE_SHORT_SERVICE did not stop within its timeout:
[component name]"

رفع اشکال:

مطمئن شوید که همه سرویس‌های پیش‌زمینه‌ای محدود به زمان کارشان را تمام می‌کنند و stopForeground(int) را در محدوده زمانی سیستم فراخوانی می‌کنند.

سرویس‌های پیش‌زمینه‌ای‌تان Service.onTimeout(int,int) را پیاده‌سازی کنند. مطمئن شوید که پیاده‌سازی شما از آن روش بلافاصله stopSelf() را فراخوانی می‌کند.

استثناهای سرویس پیش‌زمینه‌ای

این بخش چندین مشکل سرویس پیش‌زمینه‌ای را شرح می‌دهد که می‌تواند باعث شود سیستم استثنایی را ایجاد کند. اگر برنامه استثنا را دریافت نکند، کاربر کادر گفتگویی می‌بیند که به او می‌گوید برنامه متوقف شده است.

در برخی موارد، سیستم استثنای داخلی ایجاد می‌کند. در این موارد، می‌توانید با نگاه کردن به ردیابی پشته‌ای متوجه شوید که استثنا چه بوده است و می‌توانید Logcat را برای اطلاعات دقیق‌تر خطا بررسی کنید.

استثنای داخلی: مهلت زمانی به‌پایان رسید

سیستم محدودیتی را اعمال می‌کند بر اینکه سرویس‌های پیش‌زمینه‌ای همگام‌سازی داده و پردازش رسانه تا چه مدت می‌توانند درحالی‌که برنامه در پس‌زمینه است اجرا شوند. اگر سرویس از آن حد فراتر رود، سیستم متد Service.onTimeout(int,int) سرویس را فراخوانی می‌کند. این سرویس چند ثانیه برای تماس با stopSelf() فرصت دارد. اگر سرویس خودش متوقف نشود، سیستم یک RemoteServiceException داخلی ایجاد می‌کند که باعث ازکارافتادن برنامه می‌شود.

عیب‌یابی:

با نگاه کردن به ردیابی پشته‌ای می‌توانید متوجه شوید که استثنا چه بوده است و برای اطلاعات دقیق‌تر درباره خطا می‌توانید Logcat را بررسی کنید. در این مورد، Logcat پیام خطای زیر را دارد:

Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout: [component name]"

رفع اشکال:

مطمئن شوید که همه سرویس‌های پیش‌زمینه‌ای با محدودیت زمانی کارشان را تمام می‌کنند و stopForeground(int) را در محدوده زمانی سیستم فراخوانی می‌کنند.

سرویس‌های پیش‌زمینه‌ای‌تان Service.onTimeout(int,int) را پیاده‌سازی کنند. مطمئن شوید که پیاده‌سازی شما از آن روش بلافاصله stopSelf() را فراخوانی می‌کند.

استثنای داخلی: ForegroundServiceDidNotStartInTimeException

وقتی سرویسی را با فراخوانی context.startForegroundService() راه‌اندازی می‌کنید، آن سرویس چند ثانیه فرصت دارد تا با فراخوانی ServiceCompat.startForeground() خود را به سرویس پیش‌زمینه‌ای ارتقا دهد. اگر سرویس این کار را انجام ندهد، ForegroundServiceDidNotStartInTimeException داخلی ایجاد می‌کند.

عیب‌یابی:

با نگاه کردن به ردیابی پشته‌ای می‌توانید متوجه شوید که استثنا چه بوده است و برای اطلاعات دقیق‌تر درباره خطا می‌توانید Logcat را بررسی کنید. در این مورد، Logcat پیام خطای زیر را دارد:

android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()

رفع اشکال:

مطمئن شوید که همه سرویس‌های پیش‌زمینه‌ای جدیداً ایجادشده ServiceCompat.startForeground() را ظرف چند ثانیه فراخوانی می‌کنند.

WorkManager:

همچنین ممکن است این استثنا را با WorkManager عامل‌هایی که سرویس پیش‌زمینه‌ای را اجرا می‌کنند (فراخوانی setForegound یا setForegroundAsync) ببینید. وقتی چرخه حیات دو عامل پیش‌زمینه‌ای هم‌پوشانی داشته باشد، به‌طوری‌که یک عامل تلاش کند سرویس پیش‌زمینه‌ای را شروع کند درحالی‌که سرویس پیش‌زمینه‌ای که قبلاً درحال اجرا بوده است تلاش می‌کند خاموش شود، این خرابی با گزارش زیر همراه خواهد بود:

Re-initializing SystemForegroundService after a request to shut-down

رفع مشکل این خرابی در WorkManager نسخه ۲.۱۰.۵ معرفی شده است.

اگر برنامه‌تان با این استثنا مواجه می‌شود، به جدیدترین نسخه WorkManager به‌روزرسانی کنید و هرگونه مشکل ادامه‌دار را به ردیاب مشکل WorkManager گزارش دهید.

ForegroundServiceStartNotAllowedException

خطا:

سیستم ForegroundServiceStartNotAllowedException را نشان می‌دهد.

علت:

این مشکل معمولاً زمانی رخ می‌دهد که برنامه سرویس پیش‌زمینه‌ای را از پس‌زمینه راه‌اندازی می‌کند، درحالی‌که هیچ معافیت معتبری وجود ندارد.

از Android 12 (سطح API‏ ۳۱)، برنامه‌ها اجازه ندارند سرویس‌های پیش‌زمینه‌ای را درحالی‌که برنامه در پس‌زمینه اجرا می‌شود راه‌اندازی کنند، به‌جز چند مورد استثنای خاص. اگر بخواهید سرویس پیش‌زمینه‌ای را از پس‌زمینه شروع کنید و شرایط یکی از معافیت‌ها را نداشته باشید، سیستم ForegroundServiceStartNotAllowedException را نشان می‌دهد. اگر الزامات معافیت را برآورده نکنید، سیستم این کار را انجام می‌دهد.

برای مثال، ممکن است برنامه‌ای دکمه‌ای داشته باشد که کاربر بتواند روی آن کلیک کند و این کار باعث شود برنامه پردازشی انجام دهد و سپس سرویس پیش‌زمینه‌ای را راه‌اندازی کند. در این مورد، این خطر وجود دارد که کاربر روی دکمه کلیک کند و سپس بلافاصله برنامه را در پس‌زمینه قرار دهد. سپس برنامه سعی می‌کند سرویس را از پس‌زمینه راه‌اندازی کند. اگر برنامه یکی از معافیت‌های مشخص‌شده را نداشته باشد، سیستم ForegroundServiceStartNotAllowedException را نشان می‌دهد.

علاوه‌براین، برخی معافیت‌ها محدودیت زمانی کوتاهی دارند. برای مثال، اگر برنامه‌تان سرویس پیش‌زمینه‌ای را در پاسخ به پیام FCM با اولویت بالا راه‌اندازی کند، معافیت کوتاهی وجود دارد. اگر سرویس را به‌اندازه کافی سریع راه‌اندازی نکنید، ForegroundServiceStartNotAllowedException دریافت می‌کنید.

گاهی اوقات معافیت‌های خاص با انتشار نسخه‌های جدید Android محدودتر می‌شوند. اگر نسخه Android هدف برنامه‌تان را تغییر داده‌اید، سند تغییرات سرویس‌های پیش‌زمینه‌ای را بررسی کنید و مطمئن شوید برنامه‌تان همچنان یکی از معافیت‌های مجاز را دارد.

رفع اشکال:

گردش کار برنامه‌تان را تغییر دهید تا وقتی برنامه در پس‌زمینه است، نیازی به راه‌اندازی سرویس‌های پیش‌زمینه‌ای نداشته باشد، یا تأیید کنید که برنامه‌تان یکی از معافیت‌ها را دارد.

می‌توانید از مؤلفه‌های آگاه از چرخه حیات برای مدیریت چرخه حیات برنامه‌تان استفاده کنید تا به‌طور ناخواسته سرویس پیش‌زمینه‌ای را از پس‌زمینه راه‌اندازی نکنید.

SecurityException

خطا:

سیستم SecurityException را برمی‌گرداند.

علت:

برنامه شما تلاش کرد سرویس پیش‌زمینه‌ای را بدون داشتن اجازه‌های لازم راه‌اندازی کند.

  • اگر برنامه‌ای Android 9 (سطح میانای برنامه‌سازی کاربردی ۲۸) یا بالاتر را هدف‌یابی کند، باید اجازه FOREGROUND_SERVICE را برای راه‌اندازی سرویس پیش‌زمینه‌ای داشته باشد.
  • اگر برنامه‌ای Android 14 (سطح میانای برنامه‌سازی کاربردی ۳۴) یا بالاتر را هدف‌یابی کند، باید همه پیش‌نیازهای نوع سرویس پیش‌زمینه‌ای خود را برآورده کند. این پیش‌نیازها در سند انواع سرویس پیش‌زمینه‌ای به‌طور مفصل شرح داده شده است. به‌ویژه، از الزامات زیر مطلع باشید:
    • چند نوع سرویس پیش‌زمینه‌ای به اجازه‌های زمان اجرای خاصی نیاز دارند. برای مثال، سرویس پیش‌زمینه‌ای پیام‌رسانی ازراه‌دور باید اجازه FOREGROUND_SERVICE_REMOTE_MESSAGING را داشته باشد.
  • در چندین مورد، محدودیت‌های اضافی «درحین استفاده» برای اجازه‌های موردنیاز برخی‌از انواع سرویس‌های پیش‌زمینه‌ای وجود دارد. این اجازه‌ها فقط زمانی به برنامه اعطا می‌شود که برنامه در پیش‌نما باشد (با چند استثنای خاص). این یعنی حتی اگر برنامه شما یکی از این اجازه‌ها را درخواست کرده باشد و به آن اعطا شده باشد، اگر برنامه سعی کند سرویس پیش‌زمینه‌ای را درحالی‌که برنامه در پس‌زمینه است راه‌اندازی کند، سیستم SecurityException را صادر می‌کند، حتی اگر برنامه برای شروع سرویس پیش‌زمینه‌ای از پس‌زمینه معافیت داشته باشد. برای اطلاعات بیشتر، محدودیت‌های شروع سرویس‌های پیش‌زمینه‌ای که به اجازه‌های «درحین استفاده» نیاز دارند را ببینید.
    • اگر اجازه‌های لازم را درخواست کرده باشید اما سرویس پیش‌زمینه‌ای را قبل‌از تأیید اعطا شدن اجازه‌های لازم شروع کنید، ممکن است SecurityException دریافت کنید.

رفع اشکال:

قبل‌از راه‌اندازی سرویس پیش‌زمینه‌ای، همه اجازه‌های سرویس پیش‌زمینه‌ای مناسب را درخواست کنید و مطمئن شوید که همه پیش‌نیازهای زمان اجرا را برآورده کرده‌اید.