Android14 front-end service adaptation guide
Android 10 introduces theandroid:foregroundServiceType
attribute to help developers define front-end services more purposefully. This attribute is mandatory in Android 14 and the appropriate foreground service type must be specified. The following types of front desk services are available:
camera
: Camera application.connectedDevice
: Apps related to connected devices.dataSync
: Data synchronization application.health
: Health-related applications.location
: Location-related applications.mediaPlayback
: Media playback application.mediaProjection
: Media projection application.microphone
: Microphone related applications.phoneCall
: Phone calling application.remoteMessaging
: Remote messaging application.shortService
: Short-term service applications.specialUse
: Special purpose applications.systemExempted
: System exception application.
If the application's foreground service is not related to the above types, it is recommended to migrate to other methods such as WorkManager or user-triggered data transfer jobs.
It is worth noting that health
, remoteMessaging
, shortService
, are newly added in Android 14 specialUse
and systemExempted
types. The application must declare the front-end service type in the manifest file as follows:
<manifest ...>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<application ...>
<service
android:name=".MyMediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
</service>
</application>
</manifest>
For applications targeting Android 14, if no foreground service type is defined, the system will throw an exception when calling startForeground()
. This change is intended to improve app security and user privacy protection. MissingForegroundServiceTypeException
Android14 front desk service adaptation
-
Declare new permissions: When an application targeting Android 14 uses a front-end service type, it must declare specific permissions based on the front-end service type. These permissions are listed in the Intended Use Cases and Enforcement sections for each front-end service type and are labeled "Permissions you must declare in the manifest file". These permissions are general permissions and cannot be revoked by the user. If an app calls
startForeground()
but does not declare the appropriate foreground service type permissions, the system will throw anSecurityException
exception. -
Contains the foreground service type at runtime: For applications that start foreground services, it is recommended to use the overloaded version of
startForeground()
, in which one or more values of the foreground service type can be passed. In general, you should only declare front-end service types that are relevant to a specific use case. If a foreground service is started with multiple types, it should comply with the enforcement requirements of all types. -
System runtime checks: The system checks for appropriate use of the foreground service type and verifies that the app has requested the appropriate runtime permissions or used the required APIs. For example, when an application uses the
FOREGROUND_SERVICE_TYPE_LOCATION
foreground service type, it needs to requestACCESS_COARSE_LOCATION
orACCESS_FINE_LOCATION
permissions. Apps must strictly follow a specific sequence of requesting permissions and starting foreground services. The required permissions must be requested and obtained before callingstartForeground()
. If the app does not meet the runtime requirements for the foreground service, the system will throw after callingstartForeground()
, which prevents the foreground service from starting, possibly causing the app to crash.SecurityException
The Intended Use Cases and Enforcement sections for each front-end service type provide details about the platform-enforced requirements that app developers should follow to ensure proper operation of their apps.
Expected use cases and enforcement for each front-end service type
Only a few services such as cameras, connected devices, and data synchronization are explained. For more types of usage, please refer to the link below.
https://developer.android.google.cn/about/versions/14/changes/fgs-types-required?hl=zh-cn
To use a specific front-end service type, the following conditions should be met:
-
Declare specific permissions in the manifest file.
-
Meet specific runtime requirements.
-
The app must meet one of the expected set of use cases for that type.
The requirements for specific front-end service types are as follows:
-
Camera:
- Statement limit:
FOREGROUND_SERVICE_CAMERA
. - Runtime requirement: Request camera runtime permission.
- Use case: Continue to access the camera in the background, such as a video chat app that supports multitasking.
- Statement limit:
-
Connected devices:
- Statement limit:
FOREGROUND_SERVICE_CONNECTED_DEVICE
. - Runtime requirements: Specific permissions or runtime permissions must be met.
- Use case: Interact with external devices requiring Bluetooth, NFC, IR, USB or network connectivity. Use cases can include Bluetooth connectivity, network connectivity, etc.
- Statement limit:
-
data synchronization:
- Statement limit:
FOREGROUND_SERVICE_DATA_SYNC
. - Runtime requirements: None.
- Use cases: data transfer operations, such as data upload, backup, import and export, file processing, etc. This front-end service type will be deprecated and it is recommended to use WorkManager or user-initiated data transfer jobs.
- Statement limit:
-
Health (preview, new in Android 14):
- Statement limit:
FOREGROUND_SERVICE_HEALTH
. - Runtime requirements: Specific permissions or runtime permissions must be met.
- Use cases: Power long-running use cases for apps in the fitness category, such as fitness trackers.
- Statement limit:
-
Location:
- Statement limit:
FOREGROUND_SERVICE_LOCATION
. - Runtime requirement: Request permission to use location information, including
ACCESS_COARSE_LOCATION
orACCESS_FINE_LOCATION
. - Use cases: Long-running location use cases, such as navigation and location sharing.
- Statement limit:
Meeting the requirements of these front-end service types is key to ensuring that the application can properly use related functions. Developers should follow these rules in manifest files and runtime permission requests to ensure that the application can function properly as a foreground service type.
The front-end service is used for user data transmission business
In Android 14, the foreground service rules are stricter and require apps to meet conditions before they can use foreground services. Introducing a new API to specify user-initiated data transfer jobs, suitable for long-term data transfer. This type of job requires manual startup by the user with RUN_USER_INITIATED_JOBS
permissions. Improvements are aimed at improving system stability and user experience.
Start user job
To run a user-initiated job, follow these steps:
- Declare in manifest file
RUN_USER_INITIATED_JOBS
Permissions:
<manifest ...>
<uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />
<application ...>
...
</application>
</manifest>
- Use the new and methods when constructing
JobInfo
objects. It is recommended that you provide an estimated payload size, using the method:setUserInitiated()
setDataTransfer()
setEstimatedNetworkBytes()
val networkRequestBuilder = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
val jobInfo = JobInfo.Builder()
// ...
.setUserInitiated(true)
.setDataTransfer(true)
.setRequiredNetwork(networkRequestBuilder.build())
.setEstimatedNetworkBytes(1024 * 1024 * 1024)
// ...
.build()
- Schedule a job when the app is visible or when allowed conditions are met:
val jobScheduler: JobScheduler =
context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
jobScheduler.schedule(jobInfo)
- When executing a job, be sure to call for the
JobService
object, which notifies the user that the job is running:setNotification()
val notification = Notification.Builder(applicationContext, NOTIFICATION_CHANNEL_ID)
.setContentTitle("My user-initiated data transfer job")
.setSmallIcon(android.R.mipmap.myicon)
.setContentText("Job is running")
.build()
class CustomJobService : JobService() {
override fun onStartJob(params: JobParameters?): Boolean {
setNotification(params, notification.id, notification, JobService.JOB_END_NOTIFICATION_POLICY_DETACH)
// 执行作业任务。
}
}
-
Please note that if
setNotification()
is not called in time, it may cause an ANR in the application. -
Notifications are updated regularly so users know the status and progress of their jobs. If the transfer size cannot be determined before scheduling the job, use the new API
updateEstimatedNetworkBytes()
to update the transfer size once the transfer size is known. -
After job execution is complete, call
jobFinished()
to indicate to the system that the job is complete or that the job needs to be rescheduled.
Stop user job
-
Stop a user-initiated data transfer job:
- Both the user and the system can stop a user-initiated transfer job.
- Users can stop user-initiated transfer jobs through the Stop action in Task Manager.
- When the user stops a job, the system terminates the app's processes, including any running jobs or foreground services.
- The system will not call
onStopJob()
to terminate the job and will prevent user-visible jobs from being rescheduled. - It is recommended to provide controls in published job notifications to allow users to stop and reschedule jobs.
- In some cases, the Stop button may not appear in Task Manager or the job may not appear at all.
-
Stop jobs provided by the system:
- Unlike regular jobs, user-initiated data transfer jobs are not affected by app standby mode bucket quotas.
- However, the system still stops the job for several reasons:
- The developer-defined constraints are no longer met.
- The system considers the job to be running longer than it takes to complete the data transfer.
- The system needs to prioritize system health and may stop operations due to excessive equipment temperature.
- The application process was terminated due to insufficient device memory.
- When the system stops a job (not due to insufficient memory), the system calls
onStopJob()
and retries the job at a time the system deems best. - Developers should ensure that applications retain data transfer state even when
onStopJob()
is not called, and restore the state whenonStartJob()
is called again.
User job constraints
Summarized as follows:
-
To support jobs that run at optimal times, Android provides the ability to assign constraints to each job type, available starting in Android 13.
-
Constraints allowed for user-initiated data transfer jobs include:
setBackoffCriteria(JobInfo.BACKOFF_POLICY_EXPONENTIAL)
setClipData()
setEstimatedNetworkBytes()
setMinimumNetworkChunkBytes()
setPersisted()
setNamespace()
setRequiredNetwork()
setRequiredNetworkType()
setRequiresBatteryNotLow()
setRequiresCharging()
setRequiresStorageNotLow()
test
The steps for testing an application job include:
- Get the job ID.
- The command
adb shell cmd jobscheduler run -f APP_PACKAGE_NAME JOB_ID
allows you to run or retry a stopped job immediately. - With the command
adb shell cmd jobscheduler timeout TEST_APP_PACKAGE TEST_JOB_ID
you can simulate the system forcibly stopping the job, for example due to system health conditions or exceeded quota conditions.