# Android Foreground Service Type Guide Android 14 (API 34) makes the `foregroundServiceType` mandatory for every foreground service. Android 15 (API 35) introduces a new type `mediaProcessing` specifically for image/video transcoding workloads. If your worker declares the wrong type, the OS throws `ForegroundServiceStartNotAllowedException` at runtime — no build-time warning. This guide pins down the right type per camera-app workload, plus the manifest snippets you need to paste into the host app. ## Pick the right type | Workload | Type constant | Min API | Manifest permission | |---|---|---|---| | HTTP upload / download / sync | `FGS_DATA_SYNC` (default) | 29 | `FOREGROUND_SERVICE_DATA_SYNC` (API 34+) | | Image / video transcoding | `FGS_MEDIA_PROCESSING` | 35 | `FOREGROUND_SERVICE_MEDIA_PROCESSING` | | Audio / video playback | `FGS_MEDIA_PLAYBACK` | 29 | `FOREGROUND_SERVICE_MEDIA_PLAYBACK` | | Camera capture session | `FGS_CAMERA` | 29 | `FOREGROUND_SERVICE_CAMERA` | | GPS / geofence | `FGS_LOCATION` | 29 | `FOREGROUND_SERVICE_LOCATION` | | Bluetooth peripheral | `FGS_CONNECTED_DEVICE` | 29 | `FOREGROUND_SERVICE_CONNECTED_DEVICE` | Wrong-type symptoms in production: - Android 14+ device, `dataSync` declared but `mediaProjection` actually used → `SecurityException: Starting FGS with type mediaProjection ... requires permissions`. - Android 15+ device, image compression with `dataSync` → still runs, but Play Store policy review flags the app for misusing the type. Use `mediaProcessing`. - `dataSync` on a 6+ hour upload — Android 15 limits `dataSync` to 6 hours of cumulative runtime per 24h window. Heavy nightly sync workloads hit this. ## 1. Override `foregroundServiceType` in your subclass `KmpHeavyWorker.foregroundServiceType` defaults to `FGS_DATA_SYNC`. Override it: ```kotlin // Image / video compression worker class TranscodeWorker( appContext: Context, params: WorkerParameters, factory: AndroidWorkerFactory, ) : KmpHeavyWorker(appContext, params, factory) { override val foregroundServiceType: Int get() = if (Build.VERSION.SDK_INT >= 35) { FGS_MEDIA_PROCESSING } else { FGS_DATA_SYNC // pre-Android-15 fallback } } ``` The guard against `Build.VERSION.SDK_INT >= 35` is required — `FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING` is API 35+; declaring it on older devices is a no-op at best, a crash at worst. ## 2. Host app manifest snippets ### `mediaProcessing` (Android 15+ transcoding) ```xml ``` ### `camera` (capture session continuing in background) ```xml ``` ### `location` (geofence trigger / GPS upload) ```xml ``` ## 3. Runtime permission check (recommended) Some FGS types require a runtime permission grant on top of the manifest entry. For example, `FGS_CAMERA` does nothing without `CAMERA`. Verify before scheduling: ```kotlin if (Build.VERSION.SDK_INT >= 34 && ActivityCompat.checkSelfPermission( context, Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED) { // Don't schedule — system would kill the service immediately. return } scheduler.enqueueTask(/* ... */) ``` ## 4. Android 15 `dataSync` 6-hour cap Android 15 enforces a cumulative 6-hour-per-day cap on `dataSync` FGS runtime. When the cap is hit: - `setForeground()` throws `ForegroundServiceTypeException` on subsequent runs. - WorkManager marks the work as `FAILED` (does NOT retry). For long-running uploads (camera RAW backup), prefer chunked work + a constraint on `requiresUnmeteredNetwork` so each worker instance is short-lived. The 6-hour clock resets at midnight device-local time. ## 5. Manifest type bitmask `android:foregroundServiceType` accepts a `|`-separated list. Declare every type that any of your workers might use: ```xml android:foregroundServiceType="dataSync|mediaProcessing|camera|connectedDevice" ``` The OS picks the intersection of the manifest declaration AND the type passed to `ForegroundInfo`. Declaring extras in the manifest is harmless; missing one is a crash. ## 6. Testing There is no Robolectric stub for the type check — it's a system-level guard. Integration testing approach: 1. Connect a real Android 14+ device. 2. `adb shell cmd appops set START_FOREGROUND deny` to simulate a denied FGS. 3. `adb shell dumpsys activity processes ` after scheduling — check the `foregroundServiceType` field on the running service. 4. For Android 15 6-hour cap testing: `adb shell device_config put activity_manager_native_boot fgs_data_sync_max_duration_ms 60000` (drops the cap to 1 minute for the next boot). ## See also - [Android docs — Foreground service types](https://developer.android.com/about/versions/14/changes/fgs-types-required) - [Android 15 dataSync cap](https://developer.android.com/about/versions/15/changes/datasync-timeout) - `KmpHeavyWorker.foregroundServiceType` KDoc — overrideable in subclasses