Simple Spyware
Androids Invisible Foreground Services and How to
(Ab)use Them
Whitepaper
Thomas Sutter
ID
Winterthur, Switzerland
suth@zhaw.ch
December 2019
Abstract
With the releases of Android Oreo [1] and Pie [2], Android introduced some background execution limitations
for apps. Google restricted the execution of background services to save energy and to prevent apps from running
endlessly in the background. Moreover, access to the device’s sensors was changed and a new concept named
foreground service has been introduced. Apps were no longer allowed to run background services in an idle state,
preventing apps from using the device’s resources like the camera. These limitations, however, would not affect
so-called foreground services because they show a permanently visible notification to the user and could therefore
be stopped by the user at any time. Our research found out that flaws in the API exists, which allows starting
invisible foreground services, making the introduced limitations ineffective. We will show that the found flaws
allow attackers to use foreground services as a tool for spying on users.
I. INTRODUCTION
We found out that foreground services do not show any visual notification when the service’s execution
time is shorter than ve seconds
1
. We use this loading time and combine it with another flaw in Androids
Job Scheduler API to continuously execute tasks from a background context. Exploiting these flaws allows
apps to use the device’s resources, even when the app is closed or on standby. Furthermore, we show
that we can use these flaws for continually spying on users and allowing malware developers to create
spyware without the need for complicated exploitation.
We start in Section II with some basic introduction to Android’s components and then we explain how
we spawn a foreground service on Android Pie combined with some basic background schedulers. We
then use this basic example to show how we can use these API’s to implement a simple spyware app. At
the end of the paper in Section V we discuss some limitations as well as ideas to prevent such attacks.
II. ABUSING FOREGROUND SERVICES
Android defines two basic types of service classes for apps, background and foreground services [3].
The difference between these services is how they appear in the user interface and under which constraints
they are executed. We can start Foreground services even when the user interface is closed; in contrast,
background services cannot do so. The operating system prevents background services to start when the
app’s user interface is closed by throwing an IllegalStateExeception. If we want to run a task when the
app is closed, we can use Android’s scheduling classes instead. For example, the JobScheduler [4] and
AlarmManager [5] classes.
Those schedulers’ idea is that apps can synchronize or process data even when the user interface gets
closed. We can use this, for example, to set an alarm clock or to upload a file when the user interface
is not needed. If misused, schedulers often use a lot of battery power. For example, when an app is
1
The exact duration is depending on the phone.
arXiv:2011.14117v1 [cs.CR] 28 Nov 2020
continuously uploading data in the background. Since Android Oreo and app can no longer run endless
background services when its user interface is not shown. Usually, the operating system stops all services
some minutes after the app was closed. Moreover, access to sensors like microphones and cameras should
no longer work when the app is closed. In case an app tries to access one of the restricted sensors from
a scheduler, the operating system throws an IllegalStateException, and the access is thereby not granted.
However, in order to access the sensors from the background context, foreground services can be used.
Schedulers are allowed to start foreground services, and as mentioned, foreground services do not have
any restrictions when it comes to sensor access. The only limitations foreground services have is that
they need to show a permanently visible notification and that the app spawning the foreground service
needs to have the permission to access the sensor. Listing 1 shows an example code to start a foreground
service in Java.
1 public class SomeExampleService extends Service {
2 // Start service by intent. No filtering shown here
3 @Override
4 public int onStartCommand(Intent intent, int flags, int startId){
5 // ˜4.9999.. seconds to call startForeground(...)
6 Notification notification = createCustomNotification();
7 this.startForeground(1, notification) // Sensor access not restricted anymore
8 // Race condtion started. Let’s collect some data fast...
9 accessCamera();
10 accessMicrophone();
11 // ... some more malicious code
12 stopForeground(true); //Stop the service before notification is loaded and
13 // win the race against the notification manager.
14 return START_STICKY;
15 }
16 ...
17 /
**
18
*
Create a custom notification.
19
*
/
20 private Notification createCustomNotification() {
21 NotificationChannel channel = new NotificationChannel("1", "Location",
22 NotificationManager.IMPORTANCE_LOW);
23 NotificationManager notificationManager = getSystemService(
NotificationManager.class);
24 if(notificationManager != null){
25 notificationManager.createNotificationChannel(channel);
26 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "
1")
27 .setSmallIcon(R.drawable.ic_remove_red_eye_black_24dp)
28 .setContentTitle("Simple Spyware")
29 .setContentText("Tracking your position!")
30 .setPriority(NotificationCompat.PRIORITY_LOW)
31 return builder.build();
32 }
33 }
34 }
Listing 1. Java code to spawn and abuse foreground service.
What we can see in Listing 1 is that we extend the service class and that we define a onStartCommand
method in Line 6 as we would do with a regular foreground service. To start a foreground service, we
have to define a notification. On Lines 20 to 31, we define the notification and set an example icon and
text. As shown, we can customize the appearance of the notification as we would like it to be. Figure 1
shows how such a foreground service in the user interface could look.
Fig. 1. Example of foreground notifications in the user interface.
The notification is sticky, and we cannot dismiss it until we stop foreground service or the user
manually disables the notification. Attempting to cancel the notification within Java will not work since
the notification manager will not allow it. An attacker could hide its intention by showing some typical
notification like an update, announcement, or loading screen. In many cases, as long as the notification
does not stay too long in the notification bar, it will not raise the user’s suspicion. Nevertheless, users could
get suspicious or annoyed when the notification shows them some unwanted content or the notification
stays too long in the notification bar. In such cases, the user can stop the app or disable the notifications
for the app.
As attackers, we wanted to go a step further and see if we could stop the notification from showing
up at all, so that the users would not get alarmed. So we search for possibilities to dismiss or cancel the
notification but could not find an easy way to do it. Instead, we found out that the notification manager
does not show a notification when the foreground service’s lifetime is shorter than ve seconds. We can
use this race condition to execute any code before the operating system loads the notification.
We can spawn one invisible foreground service and execute our code once, and then the app will
stop. To further abuse this approach, we needed a way to persistently spawn new foreground services
on demand. To do so we use Android’s JobScheduler [4] or AlarmManager [5] classes which allows to
execute code outside of the app context. For decided to use for our example the JobScheduler class but
the AlarmManager has more or less the same functionality. We create a new Job with the JobInfo.Builder
[6] as shown in Listing 2.
1 public void scheduleJob(){
2 long interval = 1000
*
60L; // Some interval
3 ComponentName serviceComponent = new ComponentName(this,
4 JobScheduler.class);
5 JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, serviceComponent);
6 builder.setPeriodic(interval); // Minimum is 15 minutes
7 builder.setOverrideDeadline(interval
*
2); // Sets the maximum scheduling
8 // latency
9 builder.setMinimumLatency(interval); // Runs a job after a delay
10 JobScheduler jobScheduler = this.getSystemService(JobScheduler.class);
11 jobScheduler.schedule(builder.build()); // Schedule the job
12 }
Listing 2. Java example for the job scheduler class.
As attackers, we want to use the JobScheduler to start a job every X seconds or minutes. Our idea is
that we want to execute any malicious command like taking a picture or uploading a file whenever we
need it. The JobScheduler class has a method .setPeriodc(long seconds) that offers precisely that. The
problem with this method is that it has a minimum interval of 15 minutes. So if we would use it, we
could only execute malicious code every 15 minutes. For some malicious commands, this is maybe a too
long period, so we wanted to circumvent this limitation. Instead of using the .setPeriodic method, we can
create a custom scheduler. All we have to do so is to use the JobScheduler’s .setMinimumLatency method.
This method allows us to run a job after a given delay and has no limitations in execution time. In other
words, we can set a delayed job under 15 minutes an circumvent the limitation. Consequently, we can
build our period job scheduler by chaining jobs with the delay function. Whenever we execute a job, we
schedule a new job directly with the delay method. As long as our job chain is not interrupted, we can use
the JobScheduler class to spawn new foreground services at demand. The chaining of jobs in combination
with foreground services allows us to circumvent the background service limitation introduced in Android
Oreo [1] and the background sensor access limitation introduced in Android Pie [2].
If we want, we can further enhance our scheduling with some other options of the JobScheduler class.
For example, we could only schedule jobs when the device is charging or connected to wifi. We can as
well change our scheduling strategy during execution if necessary, to stay undetected.
setPersisted(boolean isPersisted): This allows that a job persists restarts. Needs the received boot completed
permission to do so.
setRequiredNetwork(NetworkRequest networkRequest) and setRequiredNetworkType(int networkType):
This allows us to define a specific network type to be active before the job is executed.
setRequiresBatteryNotLow(boolean batteryNotLow): Run a job only if the battery is not low. Usually,
this is when the phone has more than 15% capacity.
setRequiresCharging(boolean requiresCharging): Run a job only when the device is charging.
setRequiresDeviceIdle(boolean requiresDeviceIdle): Run a job only if a device is not used and
therefore in idle state.
See [4] for a complete overview of methods. An example of this approach was implemented in our open-
source demo app [7]. This approach also works with the AlarmManager class, and the code is as well
available in our git.
III. COLLECTING DATA
After we have set up the chain of jobs and start our foreground service, we can add methods to collect
the user’s data. As shown in Listing 1 on Line 9, it is common for spyware to take camera pictures
or to record the microphone audio. We have tested if our approach works with these features, and we
implemented some examples in our demo app.
A. Camera
We can modify some of the existing open-source libraries [8]–[10] for taking hidden camera pictures
to demonstrate that we can access the camera API from the background. We start an invisible foreground
service and use our access to the camera2 API to capture some images. In most cases and with the phones
we had at hand, this approach works as expected. However, during testing, we noticed that our hidden
camera implementation does not work on all cameras. Some cameras only show black images due to a
short exposure time or wrong camera calibration.
B. Microphone
As we have explained, we use short lived foreground services with an execution time of maximal five
seconds. This execution time is for most audio recordings not sufficient, and we would generate most
likely incomplete audio recordings if we tried to record only for five seconds. However, it is possible
to record audio for a long time due to Android’s Media Server architecture [11]. Usually, if we want to
record audio, we use the MediaRecorder class [12], and we can start to record with the .start() method. As
soon as we do, our app will contact Android’s media server, and the server will start recording. Since our
app’s background limitations do not apply to the media server process, it can record the audio even if we
close our spyware app. Consequently, our app needs only to control when the audio recording needs to be
started or stopped, and we can do this within the five seconds execution time of our invisible foreground
service.
C. Location
Location tracking is another interesting feature since not only spyware developers are interested in
collecting this data. Tracking the position with an invisible foreground service has the advantage that
there is no limitation on how often we can get position updates from the location API. According to [13]
Background services are limited to request location updates a few time per hour. Consequently, when we
use foreground services, we can track the location near real-time with high precision, which is interesting
not only for spyware. However, If we track the position in real-time, it will consume a lot of battery
power, and battery optimization is likely to trigger and alarm the user.
Fig. 2. Android10 new runtime location permission.
When Android10 was released, we wanted to test if our approach still worked on the new Android
version. Google introduced with Android10 a new permission level called ”Allow only while in use”
for location tracking [14]. Moreover, since the release, new apps had to add a new permission to their
manifest, ACCESS BACKGROUND LOCATION, if they want to access the location from a background
service. However, tracking the location within a foreground services does not need this permission as long
as the service type within the manifest is set to location (see Listing 3).
1 <service android:name=".data.location.LocationTrackerService"
2 android:foregroundServiceType="location">
Listing 3. Manifest example for the new foreground service type.
We added the new type in the manifest and tested it. First, we tested it with the ”Allow all the time”
permission, and as expected, we were able to track the location within our invisible foreground service.
As a second test, we tested if the ”Allow only while in use” permission would have any effect since
we think Google created it to prevent what we were doing precisely. However, we could still track the
location of the phone. The system sees a foreground service by definition to be in the foreground and,
therefore, to be used. As a consequence, we can use an invisible foreground service and track the location
even when the app gets closed and the ”Allow only while in use” permission is set.
D. Files & Others
As the last attack, we wanted to see if we could use our foreground service to monitor the file storage.
Similar to the other attacks, we can conduct this one by running a foreground service every X minutes.
In our case we just tested if it is possible to upload files from the external storage like camera pictures
without the notification showing up. We found out that it is possible for smaller files if the data-connection
is fast enough. We could use the .setRequiresCharging and the .setRequiredNetwork method to further
improve our uploading strategy and upload larger files when the phone has the resources to do so.
When an app does not have the permissions to access the camera or the location, it may have the file
permission. Android Oreo and Pie allow an app to read all the content on the external storage where often
private critical files like photos or documents are store. An attacker can then read the information stored
in the external storage and use a foreground service to upload documents to a remote server.
We think this is primarily a problem when all pictures from the standard camera app are stored on the
external storage by default. Attackers then get direct access to all user camera pictures, which is a privacy
problem. Moreover, if the user has activated the GPS metadata tracking on the camera app, all pictures
will have the location information. So if we have the file permission, an attacker can get access to the
camera pictures and where the user has taken the pictures. Anti-virus vendors have reported such attacks
in the past [15].
We decided not to integrate this feature into our demonstration app because we would have needed to
add internet permission to our app, and we want it to be safe for testing usages. Furthermore, we tested
clip-board hijacking and overlay attacks, which also work with invisible foreground services, and decided
not to integrate them into our demo app.
IV. LIMITATIONS
In Sections III-A to III-D we demonstrated just some examples of possible attacks. All of the common
attacks are possible by using a combination of background and foreground services. Nevertheless, we
want to discuss as well the limitations of our approach.
First of all, we tested our approach only on three Android devices
2
and some Android Oreo, Pie,
and Android10 emulators. Since wide-scale testing is not feasible within this project, the foreground
2
Samsung Galaxy S9+, Samsung A50, and Huawei P smart
services may behave differently on other phones. Some vendors may have additional security measurements
implemented, which can defeat or detect invisible foreground services. As far as we know, it works on
all tested Android Oreo and Pie phones and as well on Android10 devices.
Second, we know that the access to some sensors is restricted to one app at a time: For example,
if the user has already occupied the camera, a foreground service cannot access the camera for spying.
Depending on the persistence strategy, this can occur more often than one may think and can attract the
user’s attention. For example, if our spyware captures a picture and the user has FaceID activated, it can
occur that FaceID cannot access the camera and show an error message.
Third, schedulers may not run at specific times: Android reschedule jobs and alarms, for example, when
the device goes to the idle state. If our device is for a more extended period in stand-by, the schedulers
will likely not execute our code until we use the device again. Furthermore, scheduling strategies can
differ from device to device, and therefore the task execution can work correctly on one device but not
on another.
Fourth, some vendors have different behavior for showing notifications. For example, the location icon
on some phones is shown as soon as the user activates location tracking and is permanently visible in the
top menu bar. Other vendors only show the location icon whenever an app accesses the phone’s location.
So visibility for some features is different on some devices.
Fifth, if we choose a spying strategy that uses many phone resources, like taking a camera picture every
10 seconds, it is likely that the operating system’s battery optimizations will trigger. Depending on the
phone vendor, it may show a notification to the user or directly stop the execution of our app.
Sixth, all the demonstrated malware features work only if the user has already installed the app and
has given the app the necessary runtime permissions.
V. RESULTS
Our demo spyware shows that Android’s permission model cannot prevent excessive use of permissions
and that the limitations do not prevent the collection of the user’s sensitive data. As we described, the
access restriction in Android Pie cannot entirely prevent our access to the critical sensors like the camera
over foreground services. We think the restrictions, in general, are a good idea and give the user more
security, but it still lacks some fundamental points like restricting the file access. We can summarize what
we have done in the following steps:
1) Background Scheduling: We frequently spawn new jobs with a chain of JobScheduler or Alarm-
Manager jobs. With every job we execute, we start a new short-lived foreground service.
2) Invisible Foreground Service: As long as our foreground service’s execution time is shorter than
ve seconds
3
, it will not display a notification. The operating system allows only foreground service
to access critical sensors like cameras and microphones.
3) Spying: We can use common spying techniques to collect data from the user during the five-second
window. We tested taking camera pictures, recording audio, uploading files, or tracking the user’s
location and other features. We have shown that our approach works as well on Android10.
Patching these issues is not as simple as it may seem. Since invisible foreground services only use
standard API calls, which are unlikely to be removed soon. Therefore we think that such attacks are likely
to be seen for a longer time. Even if a patch for the foreground service is released and the notification’s
behavior changes, it seems that an attacker still has some possibilities for workarounds. Access and timings
may get patched, but we think it will not entirely prevent such attacks since an attacker can still set the
notification design. Attackers maybe will come up with custom notifications that do not look suspicious
to the user.
3
Five seconds it just the average. Timing may change on other phones.
VI. DISCUSSION
A. Transparency
If we wanted to prevent such attacks with the current design, we could continuously monitor the
apps’ permission usage. In case we would find an app that misused its permission, we could revoke the
permissions. Permission monitoring apps exist but are often not accurate or widely used. For example,
Samsung’s ”App Permission Monitor” [16] logs the access, and the app notifies the user as soon as the
monitor detected suspicious permission access. Monitoring the permission usage of an app can help detect
abusive apps, but monitoring is often error-prone, and automated detection is difficult. A malicious app
may only use permissions sporadically and, therefore, stay undetected, or some apps need to access some
permissions more often than others. In general, monitoring is unlikely to solve the problem entirely, but
it could give transparency to what is running in the background to security-aware users.
Another problem we should address is that Android users cannot check which tasks are running in the
background. Staying hidden from the user allows malicious apps to run code unseen. Even if the user
does not grant any dangerous permission, it allows an attacker to collect the phone’s usage data, such as
the installed apps list.
B. Revocation
We can argue that users can deny dangerous permissions to prevent the described attacks in Section II.
However, the common problem is that many users do not fully understand which permissions are essential
for an app to work and grant the requested runtime permissions. We think this leads to the fact that some
apps have too many permissions that they do not need to function correctly. Another point is that once
we give permission, the app holds access as long as it does not revoke it. In many cases, an app needs
dangerous permission just a couple of times when the user uses the app. We suggest that the operating
system automatically revokes permissions when they are not needed and that Android implements one
time and time-based permissions. We think this could help in mitigating the time-frame a malicious app
can collect data of the users. We can argue that one-time permissions or automatic permission revocation
is not user-friendly in terms of usability, but not giving Android users the possibility to defend themselves
against such fraud is it neither.
ACKNOWLEDGMENT
I want to thank my professor Dr. Bernhard Tellenbach for encouraging me to publish this work.
Moreover, I would like to thank the Zurich University of Applied Science for supporting my research on
this topic.
REFERENCES
[1] Google. (2017, May) Background execution limits. Google Corporation. [Online]. Available: https://developer.android.com/about/
versions/oreo/background#services
[2] ——. (2019, April) Behavior changes: all apps. Google Corporation. [Online]. Available: https://developer.android.com/about/versions/
pie/android-9.0-changes-all
[3] ——, “Services overview, January 2019. [Online]. Available: https://developer.android.com/guide/components/services
[4] ——. (2019, April) Jobscheduler. Google Corporation. [Online]. Available: https://developer.android.com/reference/android/app/job/
JobScheduler
[5] ——. (2019, April) Alarmmanager. Google Corporation. [Online]. Available: https://developer.android.com/reference/android/app/
AlarmManager?hl=en
[6] ——. (2019, April) Jobinfo.builder. Google Corporation. [Online]. Available: https://developer.android.com/reference/android/app/job/
JobInfo.Builder
[7] T. Sutter. (2019, December) Simple spyware github code. [Online]. Available: https://github.com/7homasSutter/SimpleSpyware
[8] K. Patel. (2016, April) android-hidden-camera. [Online]. Available: https://github.com/hussainbadri21/android-hidden-camera
[9] TwoEightNine. (2016, April) android-hidden-camera. [Online]. Available: https://github.com/TwoEightNine/AndroidSpyCamera
[10] hzitoun. (2017, October) android-camera2-secret-picture-taker. [Online]. Available: https://github.com/botyourbusiness/
android-camera2-secret-picture-taker
[11] Google. (2019, October) Media app architecture overview. Google Corporation. [Online]. Available: https://developer.android.com/
guide/topics/media-apps/media-apps-overview
[12] ——. (2019, October) Mediarecorder overview. Google Corporation. [Online]. Available: https://developer.android.com/guide/topics/
media/mediarecorder
[13] ——. (2019, October) Privacy changes in android 10. Google Corporation. [Online]. Available: https://developer.android.com/about/
versions/oreo/background-location-limits
[14] ——. (2019, October) Privacy changes in android 10. Google Corporation. [Online]. Available: https://developer.android.com/about/
versions/10/privacy/changes
[15] J. Lister. (20.11.2019) Android malware records calls, tracks location. [Online]. Available: https://www.infopackets.com/news/10657/
android-malware-records-calls-tracks-location
[16] Samsung. (2019, October) What is app permission monitor feature and how to turn it off? [Online]. Available:
https://www.samsung.com/ae/support/mobile-devices/what-is-this-new-add-feature-app-permission-monitor-and-how-to-turn-off/