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

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

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

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

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

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

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

  • کد سرویس پیش‌زمینه که قبلاً کار می‌کرد، اکنون با خطا مواجه می‌شود
  • شما به تازگی آزمایش روی یک نسخه جدید از پلتفرم را شروع کرده‌اید، یا سطح 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() را فراخوانی می‌کند.

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

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

In some cases, the system throws an internal exception. In those cases you can find out what the exception was by looking in the stack trace , and you can check Logcat for more detailed error information.

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

سیستم محدودیتی را در مورد مدت زمان اجرای سرویس‌های همگام‌سازی داده‌ها و پردازش رسانه در پس‌زمینه، در حالی که برنامه در پس‌زمینه است، اعمال می‌کند. اگر سرویس از آن محدودیت فراتر رود، سیستم متد 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() را ظرف چند ثانیه فراخوانی می‌کنند.

مدیر کار :

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

Re-initializing SystemForegroundService after a request to shut-down

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

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

ForegroundServiceStartNotAllowedException

خطا :

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

علت :

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

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

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

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

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

رفع اشکال :

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

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

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

خطا :

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

علت :

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

  • اگر برنامه‌ای اندروید ۹ (سطح API 28) یا بالاتر را هدف قرار دهد، باید مجوز FOREGROUND_SERVICE را برای راه‌اندازی یک سرویس پیش‌زمینه داشته باشد.
  • اگر برنامه‌ای برای اندروید ۱۴ (سطح API ۳۴) یا بالاتر طراحی شده باشد، باید تمام پیش‌نیازهای مربوط به نوع سرویس پیش‌زمینه خود را داشته باشد. این پیش‌نیازها در مستندات انواع سرویس پیش‌زمینه به تفصیل آمده است. به طور خاص، از الزامات زیر آگاه باشید:
    • چندین نوع سرویس پیش‌زمینه به مجوزهای زمان اجرا خاصی نیاز دارند. برای مثال، یک سرویس پیش‌زمینه پیام‌رسانی از راه دور باید مجوز FOREGROUND_SERVICE_REMOTE_MESSAGING را داشته باشد.
  • In several cases, there are additional while-in-use restrictions on permissions needed by some foreground service types. These permissions are only granted to the app while the app is in the foreground ( with a few specific exceptions ). This means that even if your app has requested and been granted one of these permissions, if the app tries to launch the foreground service while the app is in the background, the system will throw a SecurityException even if the app has an exemption to start a foreground service from the background. For more information, see Restrictions on starting foreground services that need while-in-use permissions .
    • اگر مجوزهای لازم را درخواست کرده باشید، اما قبل از تأیید اعطای مجوزهای لازم، سرویس پیش‌زمینه را شروع کنید، ممکن است با خطای SecurityException مواجه شوید.

رفع اشکال :

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