Foreground Service in Android

Foreground Service is a special component that allows Android applications to do useful work even when they are in the background. For example, Foreground Services are involved when you listen to your favorite podcast on the go, track of your location while cycling and broadcast your gameplay on Twitch.

In this article, I’ll explain how Foreground Service works and show you how to add one into your Android application.

Service vs Foreground Service

Since Foreground Service works in the background, the prefix “foreground” can be confusing. Let’s understand why it actually makes sense.

It starts with a regular Service class. According to the official documentation:

A Service is an application component that can perform long-running operations in the background.

Android documentation.

Services were around from the earliest days of Android. Initially, they could indeed perform long-running operations in the background. However, over time, Google imposed more and more restrictions on the background work in Android apps. The goal of these restrictions was to prolong users’ battery life, improve performance and preserve privacy (e.g. some apps abused background Services to track user’s location). Google succeeded in their efforts, but, along the way, background work in Android had become so restricted, that a regular started Service became effectively useless in this context. Nowadays, even if you start a Service in your app, it’ll become idle mere minutes after the user sends your app to the background (sometimes even faster).

So, regular Service can’t support important use cases for background work: playing media, tracking location, streaming, etc. Enter Foreground Service.

Foreground Service is a Service and, just like a regular Service, Foreground Service executes in the background. However, when a process launches a Foreground Service, Android OS treats that process as though it has a foreground component (e.g. foreground Activity), so it doesn’t apply background restrictions to it. This allows Foreground Service to remain functional in situations when a regular Service would long be sleeping (or, even, the entire process would be killed).

All in all, the prefix “foreground” in the context of a Foreground Service refers to the mechanism inside Android OS that gives more resources to “foreground” processes as opposed to “background” processes. In essence, Foreground Service is just a VIP Service that gets special treatment from the operating system.

Declaring Foreground Service in AndroidManifest

Just like a regular Service, Foreground Service must be declared in your AndroidManifest.xml file:

<service
    android:name=".ForegroundService"
    android:enabled="true"
    android:exported="false"
    android:foregroundServiceType="dataSync"
    />

Please note the foregroundServiceType attribute. It will become mandatory in Android 14.

Unlike regular Service, Foreground Service requires additional permissions:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

The first permission, FOREGROUND_SERVICE, is granted to the app at installation time and should be self-explanatory.

The second permission, POST_NOTIFICATIONS, is a runtime permission that was added in API 33. As you’ll see shortly, when you implement a Foreground Service, the system forces you to create a new notification corresponding to that Service that will be shown to the user. The idea is to make sure that the user is aware of the fact that there is a Foreground Service running in the background. Well, to be precise, this had been the idea in the past, but with API 33 Google changed their mind. Starting with API 33, if you want the user to see the notification, you must explicitly get their approval by asking for this permission. If the user doesn’t grant you the permission, you’ll still be able to start your Foreground Service, but the notification won’t be shown.

Implementing Foreground Service

This is the source code of a Foreground Service. This one doesn’t do anything useful, but, for your convenience, I added comments explaining where you should plug in your own logic:

class ForegroundService: Service() {

    private lateinit var notificationManager: NotificationManager

    // onStartCommand can be called multiple times, so we keep track of "started" state manually
    private var isStarted = false

    override fun onCreate() {
        super.onCreate()
        // initialize dependencies here (e.g. perform dependency injection)
        notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    override fun onDestroy() {
        super.onDestroy()
        isStarted = false
    }

    override fun onBind(intent: Intent?): IBinder? {
        throw UnsupportedOperationException() // bound Service is a different story
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (!isStarted) {
            makeForeground()
            // place here any logic that should run just once when the Service is started
            isStarted = true
        }

        // process the command here (e.g. retrieve extras from the Intent and act accordingly)
        val demoString = intent?.getStringExtra(EXTRA_DEMO) ?: ""

        return START_STICKY // makes sense for a Foreground Service, or even START_REDELIVER_INTENT
    }

    private fun makeForeground() {
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
        )

        // before calling startForeground, we must create a notification and a corresponding
        // notification channel
        
        createServiceNotificationChannel()

        val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Foreground Service")
            .setContentText("Foreground Service demonstration")
            .setSmallIcon(R.drawable.ic_your_app_logo)
            .setContentIntent(pendingIntent)
            .build()

        startForeground(ONGOING_NOTIFICATION_ID, notification)
    }

    private fun createServiceNotificationChannel() {
        if (Build.VERSION.SDK_INT < 26) {
            return // notification channels were added in API 26
        }

        val channel = NotificationChannel(
            CHANNEL_ID,
            "Foreground Service channel",
            NotificationManager.IMPORTANCE_DEFAULT
        )
        channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        notificationManager.createNotificationChannel(channel)
    }

    companion object {
        private const val ONGOING_NOTIFICATION_ID = 101
        private const val CHANNEL_ID = "1001"

        private const val EXTRA_DEMO = "EXTRA_DEMO"

        fun startService(context: Context, demoString: String) {
            val intent = Intent(context, ForegroundService::class.java)
            intent.putExtra(EXTRA_DEMO, demoString)
            if (Build.VERSION.SDK_INT < 26) {
                context.startService(intent)
            } else {
                context.startForegroundService(intent)
            }
        }

        fun stopService(context: Context) {
            val intent = Intent(context, ForegroundService::class.java)
            context.stopService(intent)
        }

    }
}

Please note the API level checks that I added for developers who need to support older API versions. If your app’s minSdkVersion is 26+, you can remove all of them.

Starting and Stopping Foreground Service

You can start the above ForegroundService from other components by invoking this method:

ForegroundService.startService(context, "some string you want to pass into the service")

Most non-trivial Foreground Services will accept additional configuration parameters from their callers. To accommodate this requirement, just add these parameters to the signature of the above method and then push them into the intent (analogously to demoString).

To stop ForegroundService, invoke this method:

ForegroundService.stopService(context)

If you’ll need to stop the Service from within, you can also use stopSelf() method.

Android Lifecycles Course

Get comfortable with lifecycles, which are one of the trickiest aspects of Android development.

Go to Course

Summary

Now you know how to add a Foreground Service to your Android application. Hope this will spare you some time. You can find a working implementation of a Foreground Service in my open-sourced TechYourChance application.

Thanks for reading and please leave your comments and questions below.

Check out my premium

Android Development Courses

12 comments on "Foreground Service in Android"

  1. “Starting with API 33, if you want the user to see the notification, you must explicitly get their approval by asking for this permission.”

    If the user does not approve notifications for our app, will Foreground Service still have all its capabilities?

    Reply
    • If the user doesn’t grant notification permission, Foreground Service will still be started, but without a notification.

      Reply
  2. 1. About foregroundServiceType, what if I don’t have a type that fits any of the available values?
    Only on Android 14 it seems there is “specialUse”.

    2. What’s the purpose of foregroundServiceType? Yet another restriction on foreground service?

    3. Isn’t it true that on some Android versions, we had to also use startService in case the app is in the foreground and startForegroundService in case it’s in the background? On which Android version has it changed?

    4. What do you think about this article of this topic:
    https://web.archive.org/web/20230327202046/https://www.hellsoft.se/your-guide-to-foreground-services-on-andorid/
    ?
    Are there any mistakes?

    Reply
    • Hi,
      1. This is a question to ask the authors of this feature. The official guidleines for Android 14 say that if you can’t find a proper type, then you should consider WorkManager.
      2. As far as I understand, starting with Android 14, the system will check that permissions that a foreground service uses match its type. So, for example, foreground service of type “camera” must request camera permission when it’s started.
      3. I’m not familiar with this requirement, frankly. If you have any links to share, I’ll appreciate that.
      4. Sorry, I don’t have time to verify other materials.

      Reply
      • My comment wasn’t published for some reason.
        I will try to write again:

        1. Not all use cases fit WorkManager at all. For example, restrictions were added for BroadcastReciever that can be registered only at runtime now, and can’t be registered in the manifest anymore. For this, you have to have a foreground service.
        2. What happens if it doesn’t?
        3. Sadly I don’t have it. I remember that Google wrote about it on the issue tracker somewhere.
        4. It’s an article like here.

        Reply
        • Hey,
          All comments go through manual approval, and sometimes I’m busy, so it takes a while. Sorry you had to type your comment twice.

          Reply
  3. Hi,
    Have you tried running services that require confirmation from the user to continue running? For example mediaprojection. My app works fine with SDK 33, but in version 34 I get an exception when I try to start the foreground service.

    Here is the exception text:
    Caused by: java.lang.SecurityException:
    Starting FGS with type mediaProjection
    callerApp=ProcessRecord{…} targetSDK=34
    requires permissions: all of the permissions allOf=true
    [android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION]
    any of the permissions allOf=false
    [android.permission.CAPTURE_VIDEO_OUTPUT, android:project_media]

    I tried different launch options, but I couldn’t figure out what the problem was.

    Here is a link to my question on stackoverflow:
    https://stackoverflow.com/questions/77307867/screen-capture-mediaprojection-on-android-14
    Unfortunately, no one has answered it yet.

    Reply

Leave a Comment