- Android O and background services
- Background services in ANDROID O
- Background Execution Limits
- What is the service in android?
- Background vs Foreground applications:
- Why do we need to restrict the use of background services?
- What are the limitations on services starting from Android O?
- And here comes the fun part…
- How can you run background tasks?
- Scheduling your tasks using Job Scheduler API:
- Conclusion:
- Foreground services
- Services that show a notification immediately
- Request the foreground service permission
- Start a foreground service
- Kotlin
- Kotlin
- Restrictions on background starts
- Check whether your app performs background starts
- Update your app’s logic
- Exemptions from background start restrictions
- Remove a service from the foreground
- Declare foreground service types
- Example using location and camera
- Kotlin
- Example using location, camera, and microphone
- Kotlin
- Add foreground service types of Work Manager workers
- Restricted access to location, camera, and microphone
- Exemptions from the restrictions
- Determine which services are affected in your app
Android O and background services
Всем привет. Как и большенству разработчиков — мне было лень делать сложные изменения от версии к версии Андроида. Первым таким сложным изменением были -«Runtime permissions», которые пришли к нам с 6-м андроидом. Но это уже в прошлом.
Темой данной публикации будут изменения в Android Oreo. Вы можете почитать подробнее здесь. Все статьи которые я находил, с возможным вариантом решения проблем говорили «Просто наследуй сервис от JobIntentService и используй его в enqueueWork()».
Круто, да. Но не все так просто. Если заглянуть в CommandProcessor, то можно увидеть что сервис останавливается сразу после выполнения onHandleWork(). Это происходит потому, что IntentService не предназначем на выполнения сложных работ, он создан для вещей вроде: доставки ивентов, старта прочих сервисов и так далее.
Эти статьи и их решения ничем мне не помогли, так как они просто копия с developer.android.com. По этому я продолжил тестировать и искать простые варианты использования сервисов пока приложение в фоне ( в совместимости с Android O). И я нашел способ.
Используя JobIntentService можно попробовать запустить ваш сервис по старинке, но контекст предоставляемый JobIntentService не подходит для этих целей, но мы всегда можем запросить контекст приложения. Но даже когда у нас будет контекст приложения, при старте сервиса нас остановят ограничения андроида.
Что же дальше? Эти ограничения на фоновое выполнение работают только тогда, когда вы пытаетесь запустить сервис с помошью startService(), если же вы будете использовать bindService, то никаких ошибок вам андроид не выдаст. Но, в случае байнда сервис будет только создан и прикреплен к приложению и нужно это все делать вместе с созданием и реализацией ServiceConnection, по вызову которого необходимо запустить необходимый метод ( onHandleWork() или onHandleIntent() или необходимый метод вашего сервиса).
Проделывая все это я пришел к заключению что это не самый простой способ. Поэтому я написал маленькую и простую библиотеку которая может делать это все за вас. Она так же позволяет использовать фоновые сервисы без их обьявления в манифесте и создания каких-либо классов. Найти ее можно здесь.
И небольшой пример с гита:
Для того чтобы использовать 2 последних варианта — нужно пронаследовать CompatService
Пример можно найти здесь.
И возвращаясь к теме того с чего я начал «Первым таким сложным изменением были -Runtime permissions», можете так же оценить мой вариант решения этой проблемы.
Источник
Background services in ANDROID O
Background Execution Limits
Whenever an app runs in the background, it consumes some of the device’s limited resources, like RAM. This can result in an impaired user experience, especially if the user is using a resource-intensive app, such as playing a game or watching video. To improve the user experience, Android 8.0 (API level 26) imposes limitations on what apps can do while running in the background. This document describes the changes to the operating system, and how you can update your app to work well under the new limitations.
What is the service in android?
Let’s first refresh what is the service in Android? As per the android documentation:
A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface.
So, fundamentally Service is the same thing as the activity but it doesn’t have the UI component in it. So, it doesn’t have to perform smooth animation at 60 fps. That’s why it can run perform any task for the longer period of time than the activity.
There are three types of the service:
- Started Service — A service is started when an application component (such as an activity) calls startService() .
- Bound Service — A service is bound when an application component binds to it by calling bindService() .
- Scheduled Service — A service is scheduled when an API such as the JobScheduler.
Background vs Foreground applications:
To learn background execution changes, we need to know the difference between background and foreground application first.
Rule of thumb, your application will be considered as a foreground service if any of the below three cases are true:
- Your application has currently visible activity.
- Your application has foreground service running.
- Your application is connected to another foreground app by binding the service or by consuming their content providers.
If any of the above scenarios is not true in the current instance, your application is considered to be in the background.
Why do we need to restrict the use of background services?
Whenever your applications run in the background using services, your application consumes two precious resources: 1) Memory and 2) Battery.
These two are limited resources on the mobile devices and most of the low to mid-range devices doesn’t have plenty of memory or battery inside it.
Suppose, if your application is doing some very intensive tasks in the background and using the larger amount of RAM to perform that task, then this will create the very junky user experience, especially if the user is using another resource-intensive app, such as playing a game or watching a video in foreground.
As per the documentation for the started service the best practice is,
When the operation is complete, the service should stop itself.
But, many applications have long running background services, which basically runs for the infinite time to either maintain the socket connection with the server or monitor some tasks or user activity. These services create battery drain and also they constantly consume memory.
From past couple of releases of android (Starting from Marshmallow), Google is trying very hard to increase the battery life and reduce the memory consumption used by the applications by introducing the doze mode and app standby by delaying the background execution by some amount of time if the phone is idle.
But most of the time despite of knowing the downsides of the long-running services developers still use them. (Mostly because it is easy to implement and maintain rather than using other workarounds.)
What are the limitations on services starting from Android O?
Starting from Android O, if your application is in the background (check above three conditions), your application is allowed to create and run background services for some minutes.
After some minutes passed, your application will enter in the idle stage. When your application enteres in the idle stage, the system will stop all the background services just like your service calls Service.stopSelf().
And here comes the fun part…
As I discussed above, the problem of battery drain and memory consumption are mainly caused by started services. To eliminate this, Android O completely prevents the use of startService() method to start the service. If you call startService() on Android O, you will end up getting IllegalArgumentException😲.
There are some exceptions in these scenarios when your application is whitelisted temporarily for some time window. During this period, your application can create background services freely. The application will put into temporary whitelist under below situations:
- When high priority FCM message received
- Receiving a broadcas
- Executing a PendingIntent from a notification.
How can you run background tasks?
If you are building a very large android application, there might be some genuine scenarios where you need to perform some tasks in background. Since starting a service using startService() command is not an option, we need to find out another ways to perform the tasks in background.
Scheduling your tasks using Job Scheduler API:
- JobScheduler api introduced in API21 to perform background tasks.
- This API allows you to run scheduled service and the android system will batch all the services from different applications and run them together in some particular timeframe. The reason behind this is to reduce the amount of time your phone’s CPU and radio wakes up by batching the tasks together. This will consume less battery and maintains system health.
- What if your application has minSdkVersion startService(). Then after you can promote your service to the foreground service by assigning an ongoing notification using startForeground() method. But starting from Android O, you cannot use startService() anymore. So to create foreground service you have to use NotificationManager.startServiceInForeground(). This method is equivalent to creating background service and promoting it to the foreground service combine.
Conclusion:
These limitations applied to the background service will definitely provide extended battery life and also lower RAM usage. Ultimately it will make your applications smooth and your user happy.
Источник
Foreground services
Foreground services perform operations that are noticeable to the user.
Foreground services show a status bar notification, so that users are actively aware that your app is performing a task in the foreground and is consuming system resources. The notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Devices that run Android 12 (API level 31) or higher provide a streamlined experience for short-running foreground services. On these devices, the system waits 10 seconds before showing the notification associated with a foreground service. There are a few exceptions; several types of services always display a notification immediately.
Examples of apps that would use foreground services include the following:
- A music player app that plays music in a foreground service. The notification might show the current song that is being played.
- A fitness app that records a user’s run in a foreground service, after receiving permission from the user. The notification might show the distance that the user has traveled during the current fitness session.
You should only use a foreground service when your app needs to perform a task that is noticeable by the user even when they’re not directly interacting with the app. If the action is of low enough importance that you want to use a minimum-priority notification, create a background task instead.
This document describes the required permission for using foreground services, how to start a foreground service and remove it from the background, how to associate certain use cases with foreground service types, and the access restrictions that take effect when you start a foreground service from an app that’s running in the background.
Services that show a notification immediately
If a foreground service has at least one of the following characteristics, the system shows the associated notification immediately after the service starts, even on devices that run Android 12 or higher:
- The service is associated with a notification that includes action buttons.
- The service has a foregroundServiceType of mediaPlayback , mediaProjection , or phoneCall .
- The service provides a use case related to phone calls, navigation, or media playback, as defined in the notification’s category attribute.
- The service has opted out of the behavior change by passing FOREGROUND_SERVICE_IMMEDIATE into setForegroundServiceBehavior() when setting up the notification.
Request the foreground service permission
Apps that target Android 9 (API level 28) or higher and use foreground services must request the FOREGROUND_SERVICE permission, as shown in the following code snippet. This is a normal permission, so the system automatically grants it to the requesting app.
Start a foreground service
Before you request the system to run a service as a foreground service, start the service itself:
Kotlin
Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() . This method takes two parameters: a positive integer that uniquely identifies the notification in the status bar and the Notification object itself.
Note: The status bar notification must use a priority of PRIORITY_LOW or higher. If your app attempts to use a notification that has a lower priority, the system adds a message to the notification drawer, alerting the user to the app’s use of a foreground service.
Here is an example:
Kotlin
Restrictions on background starts
Apps that target Android 12 (API level 31) or higher can’t start foreground services while running in the background, except for a few special cases. If an app tries to start a foreground service while the app is running in the background, and the foreground service doesn’t satisfy one of the exceptional cases, the system throws a ForegroundServiceStartNotAllowedException .
Check whether your app performs background starts
To better understand when your app attempts to launch a foreground service while running in the background, you can enable notifications that appear each time this behavior occurs. To do so, execute the following ADB command on the development machine connected to your test device or emulator:
Update your app’s logic
If you discover that your app starts foreground services while running from the background, update your app’s logic to use WorkManager. To view an example of how to update your app, look through the WorkManagerSample on GitHub.
Exemptions from background start restrictions
In the following situations, your app can start foreground services even while your app is running in the background:
- Your app transitions from a user-visible state, such as an activity.
- Your app can start an activity from the background, except for the case where the app has an activity in the back stack of an existing task.
Your app receives a high-priority message using Firebase Cloud Messaging.
Note: When your app is in the frequent bucket or a more restrictive bucket, your high-priority FCM messages might be downgraded to normal priority. If the message’s priority is downgraded, your app can’t start a foreground service. To check the priority of an FCM message that your app receives, call getPriority() .
The user performs an action on a UI element related to your app. For example, they might interact with a bubble, notification, widget, or activity.
Your app invokes an exact alarm to complete an action that the user requests.
Your app is the device’s current input method.
Your app receives an event that’s related to geofencing or activity recognition transition.
Your app receives the ACTION_TIMEZONE_CHANGED , ACTION_TIME_CHANGED , or ACTION_LOCALE_CHANGED intent action in a broadcast receiver.
Your app receives a Bluetooth broadcast that requires the BLUETOOTH_CONNECT or BLUETOOTH_SCAN permissions.
Apps with certain system roles or permission, such as device owners and profile owners.
Your app uses the Companion Device Manager and declares the REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND permission or the REQUEST_COMPANION_RUN_IN_BACKGROUND permission. Whenever possible, use REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND .
The user turns off battery optimizations for your app. You can help users find this option by sending them to your app’s App info page in system settings. To do so, invoke an intent that contains the ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent action.
Remove a service from the foreground
To remove the service from the foreground, call stopForeground() . This method takes a boolean, which indicates whether to remove the status bar notification as well. Note that the service continues to run.
If you stop the service while it’s running in the foreground, its notification is removed.
Declare foreground service types
If your app targets Android 10 (API level 29) or higher and accesses location information in a foreground service, declare the location foreground service type as an attribute of your component.
If your app targets Android 11 (API level 30) or higher and accesses the camera or microphone in a foreground service, declare the camera or microphone foreground service types, respectively, as attributes of your component.
By default, when you call startForeground() at runtime, the system allows access to each of the service types that you declare in the app manifest. You can choose to limit access to a subset of the declared service types, as shown in the code snippets within the following sections.
Example using location and camera
If a foreground service in your app needs to access the device’s location and camera, declare the service as shown in the following snippet:
At runtime, if the foreground service only needs access to a subset of the types declared in the manifest, you can limit the service’s access using the logic in the following code snippet:
Kotlin
Example using location, camera, and microphone
If a foreground service needs to access location, the camera, and the microphone, declare the service as shown in the following snippet:
At runtime, if the foreground service only needs access to a subset of the types declared in the manifest, you can limit the service’s access using the logic in the following code snippet:
Kotlin
Add foreground service types of Work Manager workers
If your app uses Work Manager and has a long-running worker that requires access to location, camera, or microphone, follow the steps to add a foreground service type to a long-running worker, and specify the additional or alternative foreground service types that your worker uses. You can choose from the following foreground service types:
Restricted access to location, camera, and microphone
To help protect user privacy, Android 11 (API level 30) introduces limitations to when a foreground service can access the device’s location, camera, or microphone. When your app starts a foreground service while the app is running in the background, the foreground service has the following limitations:
- Unless the user has granted the ACCESS_BACKGROUND_LOCATION permission to your app, the foreground service cannot access location.
- The foreground service cannot access the microphone or camera.
Exemptions from the restrictions
In some situations, even if a foreground service is started while the app is running in the background, it can still access location, camera, and microphone information while the app is running in the foreground («while-in-use»). In these same situations, if the service declares a foreground service type of location and is started by an app that has the ACCESS_BACKGROUND_LOCATION permission, this service can access location information all the time, even when the app is running in the background.
The following list contains these situations:
- The service is started by a system component.
- The service is started by interacting with app widgets.
- The service is started by interacting with a notification.
- The service is started as a PendingIntent that is sent from a different, visible app.
- The service is started by an app that is a device policy controller that is running in device owner mode.
- The service is started by an app which provides the VoiceInteractionService .
- The service is started by an app that has the START_ACTIVITIES_FROM_BACKGROUND privileged permission.
Determine which services are affected in your app
When testing your app, start its foreground services. If a started service has restricted access to location, microphone, and camera, the following message appears in Logcat:
Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.
Источник