Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Guide to Foreground Service (Droidcon Berlin 2024)

Guide to Foreground Service (Droidcon Berlin 2024)

Foreground services are an essential component for executing long-running work on Android. Android 14 includes breaking changes related to foreground services that need to be incorporated if you want to target SDK version 34.

In this session, we will cover what a foreground service is on Android, what has changed in the new Android version, and what you need to do to update your apps to target the latest SDK version. You will learn what foreground service types are and what common errors to watch out for.

We will also take a practical look at how to correctly implement foreground services using a sample project.

Leave this session confident you can work with foreground services and update your existing app to target the latest SDK version.

https://landomen.github.io/talks/

Domen Lanišnik

July 05, 2024
Tweet

More Decks by Domen Lanišnik

Other Decks in Programming

Transcript

  1. What is a Foreground Service? • Perform long-running operations •

    Continue user actions in the background • Noticeable to the user (status bar noti fi cation) • Examples: • Music player app (like Spotify) • Navigation app (like Google Maps) • Fitness app (like Samsung Health) Overview
  2. When to choose a foreground service? Coroutines RxJava WorkManager <

    3 minutes CompanionDevice Manager Geofence API https://developer.android.com/develop/background-work/background-tasks#categories_of_background_tasks Continue task while app in background? Asynchronous work Okay if task deferred or interrupted? Task scheduling APIs Short, critical task? shortService foreground service Alternative API available? Alternative API Foreground service No Yes Yes Yes Yes No No No
  3. Android 9
 API 28 Introduces FOREGROUND_SERVICE permission Android 10 API

    29 Introduces foregroundServiceType property that is mandatory for location type Android 11 API 30 New camera and microphone foreground service types Restrictions to access camera and microphone when FGS started from background Android 12 API 31 Restrictions on starting a FGS while in the background Android 13 API 33 Introduces noti fi cation permissions and FGS noti fi cations can be dismissed Android 14 API 34 Declaring foregroundServiceType property becomes mandatory Introduces health, remoteMessaging and special types Android 15 API 35 New mediaProcessing foreground service type BOOT_COMPLETED receivers are not allowed to launch some types of foreground services
  4. Foreground Service Types • Describes what kind of work the

    service does • Needs to be declared in the manifest and in the service • Mandatory with Android 14 for correct usage of FGS and consistency across device manufacturers • Each type has runtime prerequisites that need to be ful fi lled • A service can de fi ne multiple types
  5. Foreground Service Types camera connectedDevice dataSync health location mediaPlayback mediaProjection

    microphone phoneCall remoteMessaging shortService* specialUse* systemExempted* mediaProcessing https://developer.android.com/develop/background-work/services/fg-service-types
  6. Foreground Service Types <!-- Request the speci fi c foreground

    service permission for each declared type --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" /> <uses-permission android:name=“android.permission.FOREGROUND_SERVICE_CAMERA" /> <!-- Request the general foreground service permission --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  7. Play Console Declaration • For each FGS type you declare:

    • Describe app functionality • Describe user impact if task 
 deferred or interrupted • Include a link to a demo video • Select from a pre-de fi ned list of
 use cases https://developer.android.com/develop/background-work/services/fg-service-types#google-play-enforcement • Required when targeting Android 14 and above
  8. location Foreground Service Types • For long-running use cases that

    require location like navigation apps • Required from Android 10 and newer • Runtime prerequisites: • Enabled location services • ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION runtime permissions • Alternative APIs: • Speci fi c locations -> GeofenceAPI
  9. connectedDevice Foreground Service Types • When interacting with an external

    device through Bluetooth, NFC, USB or network connection • Runtime prerequisites (at least one of the following): • Declare one of the permissions in manifest: • CHANGE_NETWORK_STATE, CHANGE_WIFI_STATE, CHANGE_WIFI_MULTICAST_STATE, NFC, TRANSMIT_IR • One of the runtime permissions: • BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE, BLUETOOTH_SCAN, UWB_RANGING • Call UsbManager.requestPermission()
  10. connectedDevice Foreground Service Types • Alternative APIs: • Continuous data

    transfer to external device -> CompanionDeviceManager • Scan for BT devices -> Bluetooth scan API
  11. dataSync Foreground Service Types • Data transfer operations like upload

    or download, backup, … • Will be deprecated in future Android versions, recommended to migrate • Alternative APIs: • User Initiated Data Transfer • WorkManager (expedited work) • shortService type • Runtime prerequisites: None https://developer.android.com/about/versions/15/changes/datasync-migration
  12. mediaProcessing Foreground Service Types • New in Android 15 •

    For performing time-consuming operations on media assets, like converting media to di ff erent formats • Time limit of 6 hours per 24h • System will call Service.onTimeout(int, int) if limit is reached • Runtime prerequisites: None
  13. shortService* Foreground Service Types • Quickly (3 min) fi nish

    critical work that cannot be interrupted or postponed • Timer starts from when startForeground() is called • Need to call stopSelf() or stopForeground() when work is fi nished • System will call Service.onTimeout(int) if limit is reached • Runtime prerequisites: None • Doesn’t require Play Console justi fi cation
  14. specialUseCase* Foreground Service Types • For valid use cases that

    are not covered by other FGS types • Requires providing explanation for the Play Console review • Runtime prerequisites: None
  15. FGS Notification • Displaying a noti fi cation is required

    when starting a FGS • Visible for the duration of the service • Requires channels, runtime permissions, … • Android 12+, system waits 10 seconds before 
 showing noti fi cation • Android 13+, dismissible -> app shown in task manager
  16. How to create a Foreground Service? 1. Create a Service

    and call startForeground() or 2. Use WorkManager to de fi ne a long-running Worker by calling startForeground()
  17. class ExampleForegroundService : Service() { override fun onStartCommand(intent: Intent?, fl

    ags: Int, startId: Int): Int { // TODO Start as foreground service return super.onStartCommand(intent, fl ags, startId) } } 1. Create a service
  18. <service android:name=".service.ExampleForegroundService" android:exported="false" android:foregroundServiceType="location" /> 2. Declare service in Manifest

    <!-- Request location permission to be able to use the location foreground service type --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  19. 3. Declare FGS permissions <!-- Request the general foreground service

    permission --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Request the speci fi c foreground service permission for each declared type --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
  20. 3. Declare FGS permissions Common errors java.lang.SecurityException: Permission Denial: startForeground

    from pid=8589, uid=10623 requires android.permission.FOREGROUND_SERVICE java.lang.SecurityException: Starting FGS with type location targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_LOCATION]
  21. 4. Call startForeground() // promote service to foreground service ServiceCompat.startForeground(

    this, // service 1, // noti fi cation ID noti fi cation, // actual noti fi cation to display if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // mandatory FGS type ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION } else { 0 } )
  22. 4. Call startForeground() • Can pass multiple types by using

    the or operator • Can declare a subset of types and call startForeground() multiple times ServiceCompat.startForeground( this, 1, noti fi cation, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION or ServiceInfo.FOREGROUND_SERVICE_MEDIA_PLAYBACK } else { 0 } )
  23. 4. Call startForeground() • Passing 0 for foregroundServiceType android.app.InvalidForegroundServiceTypeException: Starting

    FGS with type none targetSDK=34 has been prohibited Common errors java.lang.IllegalArgumentException: foregroundServiceType 0x00000002 is not a subset of foregroundServiceType attribute 0x00000000 in service element of manifest fi le • Passing a type that is not declared in manifest
  24. 4. Call startForeground() • startForeground() has to be called within

    10 seconds of receiving onStartCommand() Common errors cont. android.app.ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground()
  25. 4. Call startForeground() Noti fi cations fun buildNoti fi cation(context:

    Context): Noti fi cation { createNoti fi cationChannel(context)
 return Noti fi cationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle("Title") .setContentText("Description") .setSmallIcon(R.drawable.ic_launcher_foreground) .setForegroundServiceBehavior(Noti fi cationCompat.FOREGROUND_SERVICE_DEFAULT) .setContentIntent(Intent(context, MainActivity::class.java).let { noti fi cationIntent -> PendingIntent.getActivity(context, 0, noti fi cationIntent, PendingIntent.FLAG_IMMUTABLE) }) .build() } FOREGROUND_SERVICE_IMMEDIATE FOREGROUND_SERVICE_DEFERRED
  26. 5. Start the service Crash java.lang.SecurityException: Starting FGS with type

    location targetSDK=34 requires permissions: - all of the permissions allOf=true - [android.permission.FOREGROUND_SERVICE_LOCATION] - any of the permissions allOf=false - [android.permission.ACCESS_COARSE_LOCATION, android.permission.ACCESS_FINE_LOCATION]
  27. 6. Request runtime permissions private val locationPermissionRequest = registerForActivityResult( ActivityResultContracts.RequestPermission()

    ) { granted -> if (granted) { // Precise location access granted, service can run startForegroundService() } else { } } locationPermissionRequest.launch(ACCESS_FINE_LOCATION)
  28. override fun onStartCommand(intent: Intent?, fl ags: Int, startId: Int): Int

    { val fi neLocationPermission = PermissionChecker.checkSelfPermission(this, ACCESS_FINE_LOCATION) if ( fi neLocationPermission != PermissionChecker.PERMISSION_GRANTED) { // stop the service if we don't have the necessary permissions stopSelf() } else { startAsForegroundService() startLocationUpdates() } return super.onStartCommand(intent, fl ags, startId) }
  29. • stopForeground(notificationBehavior: Int) for removing the service from foreground (does

    NOT stop the entire service) • STOP_FOREGROUND_REMOVE • STOP_FOREGROUND_DETACH • STOP_FOREGROUND_LEGACY • stopSelf() for stopping the entire service 8. How to stop the service?
  30. Create FGS using WorkManager • WorkManager has built-in support for

    long running workers • Manages and runs a foreground service on your behalf • These Workers can run longer than 10 minutes • Examples: uploads/downloads, local ML models, … • Same rules around FGS types and pre-requisites apply • Use setForeground() in your Worker https://developer.android.com/develop/background-work/background-tasks/persistent/how-to/long-running
  31. 1. Declare FGS service and permissions <!-- Request location permission

    to be able to use the location foreground service type --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  32. class ForegroundWorker( private val appContext: Context, params: WorkerParameters ) :

    CoroutineWorker(appContext, params) { override suspend fun doWork(): Result { setForeground(createForegroundInfo()) processLocationUpdates() return Result.success() } private fun createForegroundInfo(): ForegroundInfo { ... } } 2. Create Worker
  33. private fun createForegroundInfo(): ForegroundInfo { Noti fi cationsHelper.createNoti fi cationChannel(appContext)

    val noti fi cation = Noti fi cationsHelper.buildNoti fi cation(appContext) return ForegroundInfo( 1, // noti fi cation ID noti fi cation, // Noti fi cation object if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION } else { 0 } ) } 3. Create ForegroundInfo
  34. 5. What to watch out for? • Declare FGS types

    like with Service • Check for required runtime permissions before starting the work • Only use when the work is important to the user • Also requires Play Store declaration
  35. Background restrictions • Apps targeting Android 12 or newer can’t

    start FGS from background* • App has a visible window or activity in back stack or started recently • User performs an action on a UI element (noti fi cation, widget, bubble) • App receives a high-priority message using FCM • Exact alarms • App receives BOOT_COMPLETED action* • … https://developer.android.com/develop/background-work/services/foreground-services#background-start-restriction-exemptions
  36. While-in-use permission restrictions Camera, location, microphone • Permissions only apply

    while app is in the foreground • Can’t start a FGS from background that requires 
 permissions for which the app only has a 
 while-in-use permissions • pre-A14 -> FGS will launch, but result in an exception • after-A14 -> exception when creating FGS • Recommended to only launch this 
 FGS type while app has visible activity https://developer.android.com/develop/background-work/services/foreground-services#wiu-restrictions
  37. Summary • Android 14 brought a lot of changes related

    to FGS • Can start FGS using Service or WorkManager • Need to declare FGS types and ful fi ll runtime pre-requisites • Fill-out Play Store Declaration • Consider using alternative APIs
  38. Sample app • Starting a FGS of type location from

    UI • Requesting runtime permissions before starting FGS • Binding to the FGS from Activity to display 
 the service status and location updates • Stopping the service from the UI • Using WorkManager to launch a FGS* https://github.com/landomen/ForegroundService14Sample