Want to keep learning?

This content is taken from the University of Southampton's online course, Secure Android App Development. Join the course to learn more.

Securing Services

An app can interact with a Service in one of three ways. It can start the Service by calling startService(), it can bind to the Service by calling bindService(), or since Android 5.0 it can use the JobScheduler to run a Service.

Both startService() and bindService() take an Intent as an argument.

Unlike Activities, where the user can immediately see which Activity has started, calling startService() or bindService() with an implicit Intent is a security hazard, as you cannot be sure which service will respond, and the user has no way to tell.

Important: never pass an implicit Intent to startService() or bindService(). In Android 5.0 (API level 21) onwards, bindService() throws an exception if called with an implicit Intent.

Like Activities, Services can be secured by adding an appropriate permission to the <service> element in the app’s AndroidManifest.xml file. This ensures that only apps with that permission can start or bind to the Service.

<manifest >
  <application >
    <service android:name="com.example.myamazingapp.SomeService"

Given the potential security hazard with Services and implicit Intents, you should carefully consider whether your Service should specify an Intent Filter, and even whether your Service should be public at all. If your Service does not specify an Intent Filter then it can only be accessed via explicit Intents.

Securing Bound Services

A call to bindService() returns an IBinder object from the Service (indirectly since bindService() is asynchronous). The IBinder object provides the interface by which the component can make synchronous (RPC like) method invocations on the Bound Service.

The actual interface exposed by the Service is specific to that Service, and the methods available are not declared within the app’s AndroidManifest.xml file, so they cannot be given their own permissions via the manifest. They do however inherit permissions from the enclosing service (as specified in the app’s AndroidManifest.xml file).

It is best therefore to structure your app so that the methods of a Bound Service do not need specific permission checks.

However, if methods of the bound interface do require specific permission checks, then this can be done programatically by calling checkCallingPermission() with the required permission.

This will return whether the component that is invoking the method of the Bound Service has the specified permission, but doing this is potentially error prone, as you may miss a path through your code and fail to check the caller’s permission in all cases.

If at all possible specify Bound Service permissions via the app’s AndroidManifest.xml file. If different methods provided by a Bound Service require different permission checks, consider splitting the Bound Service into several separate Services, as this is possibly an indication that the methods do not logically belong together.

Properly securing Bound Services is beyond the scope of this introductory course.


In Android 5.0 (API level 21) the JobScheduler was introduced. This is intended for Services which an app runs in its own process (as jobs), and the JobScheduler will aim to schedule the jobs in an intelligent way.

The JobScheduler introduces the JobService class which extends the base Service class with an onStartJob() method that is called when the job is executed.

Every JobService must be given the following permission in the AndroidManifest.xml file.

<manifest >
  <application >
    <service android:name="com.example.myamazingapp.SomeJobService"

The permission BIND_JOB_SERVICE is defined with the signature protection level, and therefore can only be granted to the Android platform itself. This means only the JobScheduler is able to run the JobService.

Share this article:

This article is from the free online course:

Secure Android App Development

University of Southampton