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

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

این سند به بررسی مسائل زیر می‌پردازد:

قبل از اینکه عیب یابی کنید

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

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

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

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

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

خطاهای عدم پاسخگویی برنامه (ANR)

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

سرویس کوتاه مدت خیلی طولانی اجرا می‌شود و باعث ANR می‌شود.

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

تشخیص :

اگر 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() را فراخوانی می‌کند.

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

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

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

استثنای داخلی: مهلت زمانی تمام شد

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

تشخیص :

شما می‌توانید با نگاه کردن به stack trace متوجه شوید که خطا چه بوده است و می‌توانید 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 رخ می‌دهد.

تشخیص :

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

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

رفع اشکال :

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

ForegroundServiceStartNotAllowedException

خطا :

سیستم خطای ForegroundServiceStartNotAllowedException صادر می‌کند.

علت :

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

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

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

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

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

رفع اشکال :

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

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

استثنای امنیتی

خطا :

سیستم خطای SecurityException صادر می‌کند.

علت :

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

  • اگر برنامه‌ای اندروید ۹ (سطح API 28) یا بالاتر را هدف قرار دهد، باید مجوز FOREGROUND_SERVICE را برای راه‌اندازی یک سرویس پیش‌زمینه داشته باشد.
  • اگر برنامه‌ای برای اندروید ۱۴ (سطح API ۳۴) یا بالاتر طراحی شده باشد، باید تمام پیش‌نیازهای مربوط به نوع سرویس پیش‌زمینه خود را داشته باشد. این پیش‌نیازها در مستندات انواع سرویس پیش‌زمینه به تفصیل آمده است. به طور خاص، از الزامات زیر آگاه باشید:
    • چندین نوع سرویس پیش‌زمینه به مجوزهای زمان اجرا خاصی نیاز دارند. برای مثال، یک سرویس پیش‌زمینه پیام‌رسانی از راه دور باید مجوز FOREGROUND_SERVICE_REMOTE_MESSAGING را داشته باشد.
  • در چندین مورد، محدودیت‌های اضافی در هنگام استفاده در مورد مجوزهای مورد نیاز برخی از انواع سرویس‌های پیش‌زمینه وجود دارد. این مجوزها فقط در حالی که برنامه در پیش‌زمینه است به برنامه اعطا می‌شوند ( با چند استثنای خاص ). این بدان معناست که حتی اگر برنامه شما یکی از این مجوزها را درخواست کرده و به آن اعطا شده باشد، اگر برنامه سعی کند سرویس پیش‌زمینه را در حالی که برنامه در پس‌زمینه است راه‌اندازی کند، سیستم یک SecurityException ایجاد می‌کند، حتی اگر برنامه معافیتی برای شروع یک سرویس پیش‌زمینه از پس‌زمینه داشته باشد. برای اطلاعات بیشتر، به محدودیت‌های شروع سرویس‌های پیش‌زمینه که به مجوزهای هنگام استفاده نیاز دارند ، مراجعه کنید.
    • اگر مجوزهای لازم را درخواست کرده باشید، اما قبل از تأیید اعطای مجوزهای لازم، سرویس پیش‌زمینه را شروع کنید، ممکن است با SecurityException مواجه شوید.

رفع اشکال :

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