At Your Service: Timelining Android Usage with System Services

My phone runs about 200 services at any given time, and I bet yours does too, yet I have not seen these services queried as part of a forensic investigation. Is this because there’s very little worthwhile data there? Is it because it’s too difficult or time-consuming? Is it because all this information is gathered by the logical client of your favourite extraction software?

Before I answer those, there is one caveat, or speedbump, when it comes to services: most services forget or squirrel away their data on reboot, and many have length- or time-limits. This means for best results, the phone must be examined as soon after seizure as possible, and must have remained powered on. But on to the best results, and answers to those questions.

Services manage a massive amount of data, and they have to keep track of what’s going on. Thankfully, most services built in to Android answer to the dumpsys command, and they spew out a plaintext report we can dig through looking for important artefacts (and though not strictly logs, I will be referring to them as such throughout for ease). This information could possibly be gathered through a custom forensic app because services have accessible APIs – at least the one’s I checked – but that’s changing data and, frankly, using time we don’t need to spend. As I implied, running dumpsys over ADB is all we need. Once we have the data, it needs processing, and a lot of the time this processing is just formatting into something more readable. I have written a Python script which does the dumping and processing, which you can find here and build on for your own needs.

I start with a mock-up case study below, then go on to discuss individual services in more detail. Since the worth of these results rely on the timestamps, I would remind everyone to be as cautious as usual when it comes to device-recorded timestamps. My script does check current time and uptime during its operation, but can do nothing to guess clock adjustment history.

Case Study: “I Wasn’t On My Phone, Officer”

Whether or not someone was using their phone around the time of a traffic collision or other vehicle incident is a common line of enquiry, and evidence from the phone can be hazy a percentage of the time. This is when I see the most potential of interrogating Android services, rather than apps. In this hypothetical case, I was involved in a collision shortly after 20 past 5 in the evening of 09/03/21, and a 999 call was made at 17:26.

As an officer attending the scene or as part of a digital forensic investigation unit, you perform a logical client and filesystem extraction on my encrypted Android 10 handset. There is no internet history or call history from around the time, no SMS or 3rd-party app messages sent, and the recents stack doesn’t show anything like YouTube or Netflix. You could put in for telecoms data, but you have nothing to go on right now. Or do you?

Enter the services.

Normally, a logical or backup extraction doesn’t recover WhatsApp data (without APK downgrades), but here we can clearly see an interaction with the audio service where recording started then stopped 7 minutes later. That’s not edited, that’s straight out of the service dump.

[I’ll state that I’ve haven’t tested what audio messages/voice clips appear as in this log, but I would argue that when you are primarily relying on audio service logs, whether the user started a call or started a voice recording is not relevant – it is that their attention is taken by this communication.]

You could break out the “we got ‘im” banner right now, since that is evidence not only that I was on a WhatsApp call, but that I deleted the log afterwards, but you want to dig deeper…

There’s another section in the audio service log that might help – phone state.

That seems pretty conclusive. However, these entries can’t tell you which direction the call was. Did I make the call, or did someone call me? My phone is currently in silent/ vibrate only mode, and there is no log entry for the ringer playing a ringtone, so that’s inconclusive.

The vibrator service logs all generated vibrations. There’s interesting information in there about waveform and duration. A short vibration might be a notification, and often is, being logged as such by the vibrator service. Longer duration means the phone was vibrating for a while, which adds weight to the idea that someone called me. In fact, the log is split nicely into groups like “ringer”, “notification”, and “alarm”. Since the audio service logged that my phone was in “communication mode”, you can check the ringer section of the vibrator log and find that WhatsApp used the vibrator like this: 

Amplitudes0255025502550
Waveform Timings (ms)03004003004003001000

[I formatted it from a single line of text to this table for illustrative purposes. Another illustration would be “bzz, bzz, bzzzzzzz”, and I’ve never experienced that vibration dialling out, only on incoming calls.]

This heavily indicates the call was incoming – absence of this might, but not certainly, support an outgoing call.

Now for appops. The bulk of this log records recent permission usage, and organises neatly by app, then by permission. At first glance, this service isn’t that useful forensically, but the permissions coded into an app or granted by the user at install and run time are checked each time an activity calls on them, and the most recent check is logged by the appops service.

[I say check, because denials/rejections are logged too.]

There’s the audio recording permission check. Note: this is at 17:22 after a duration of 7 minutes, when the permission was last needed. Following that, the TAKE_AUDIO_FOCUS permission is timestamped to the beginning of the call.

Apparently, WhatsApp needs the ability to mute the microphone during calls (or equally possible, Android permissions are a bit clunky). Below that, both read and write access to the “external” storage (emulated /sdcard partition, the public storage area) is needed.

[I haven’t investigated why. I initially thought it was writing to the backup databases, but then subsequent messages should have made the same checks. Then I thought it was looking for a contact photo, but why would it need write access? Maybe it’s clunky permissions again.]

Finally above, the permissions to read media audio and use vibration are also checked at the beginning of the call.

The batterystats service logs all significant uses of battery by apps. What counts as significant use? Moving to the front of the screen.

The timestamps need converting from the log but you can see that the home/launcher was knocked from the top to be replaced by WhatsApp by the ±top flags.

[Batterystats is discussed later in a bit more detail]

Unfortunately, the contact name and number are just about the only things not logged.

Case Study Conclusion

Even if this data was not to be used evidentially, it could be a great aid when constructing a timeline or interview strategy. These are just a few of the services running on Android, and I would say conclusively prove that a WhatsApp voice call was received and answered on that handset, and the driver was in a call at the time of the crash. If the phone had connected to Bluetooth, that would have been logged too, perhaps being instrumental in deciding between Dangerous Driving and lesser charges.

Notes on Individual Services

As I said at the top, there are around 200 services running on (my) Android and I’m not going to cover all of them. Below are comments on a selection of useful services.

Audio

The OpenSL ES audio player default to Android appears to have a 5 seconds “cooldown”, such that instances of audio playing within 5 seconds of the end of another instance will keep the audio player alive. At the end of this 5 seconds, audio control is released and the process dies. I think this is not forensically significant, as I see little value in tracking process IDs when identifying whether audio was playing or not.

What could be very important, is that the events logged by this service do not mean that the audio was audible. If the phone volume is muted, the audio will play but cannot be heard – the speaker will not be activated and used. Phone volume may not have a detailed historic log, but the current levels are monitored by the same service as we got this data:

More may profiles exist – this is simply illustrative

Adjustments to volume by stream are logged by the same service.

Batterystats

Firstly, you should know there is a batterystats explorer[link] maintained apparently as part of Android developer tools. I found that the page was last updated in May 2016, so may not handle current Android stats. It presents a nice overview and can give per-app visualisations. Example:

https://developer.android.com/topic/performance/power/battery-historian

This appears great in isolation, but manages to have a lot of data likely extraneous to forensic purposes and only logs notable battery usage. The decoding in my script may not be as thorough as the official program, but combines batterystats with the data from other services.

In my testing, batterystats’ logging seemed to consistently reset each morning the phone was taken off charge. That reset is also indicated in the official screenshot above. But what’s actually in the log? First, I noticed a fun quirk where the timestamps are relative to the start of the log.

This doesn’t present too much difficulty though. What does, is that multiple events can be logged per line (which implies there’s a tiny buffer or queue that is read on a tick).

Another thing I’ve found is that audio control is released and reacquired periodically while in use. One line in the log may contain the –audio flag, and the following line have +audio. This reacquisition may even be within a couple of milliseconds of the release (and the user would never hear the “gap”). I’ve not delved that deep into Android source code to find out why, I’ve simply accommodated this quirk in my script: using audio, such as in a call, for half an hour logs possibly hundreds of battery usage events, so my script ignores these blips and presents the usage as a block with a single start event and single end event.

Unfortunately, batterystats does not record which package is using audio. If we have to rely only on batterystats alone, we have to do some interpretation and inspect the battery usage around the first audio event of a block.

Raw output of batterystats dump

At the time of those log entries, only Google Music was playing audio on the phone, but we can’t categorically state that from the information in the log. This log should be combined with others for verification, but it is certainly indicative of usage that the only services active (particularly +fg entries) around that first instance of +audio are from com.google.android.music. These job and sync events are background processes by the app, so may be diagnostic but not forensically significant, only telling us that an app service was active. Serious note should be taken that these can be active when there is no user interaction with the app, and these should just be seen as informative or corroborating data. The only flag that can inform us of direct user interaction is top, where an app is made visible on the screen, though things like full screen alarms will also create top entries.

One last thing – batterystats records when the power button is used to wake the device, but not when it is used to put the device to sleep (because that doesn’t use power),

Deviceidle

This is dependent on the Doze feature built in to Android 6 and onward. When the device is in idle or deep-idle mode, various services are suspended in order to save battery, so timers and events may be postponed until a periodic maintenance window (a single line of communication previously called GCM but now called FCM is kept open and managed by Android during doze so that messaging apps can still get real-time updates if coded correctly, and alarms can still be raised as frequently as every 9 minutes). These idle modes have checks and timers so they don’t activate when phone is in use. The deviceidle output includes a list of time conditions for entering these idle states.

It’s not super-easy to understand what all of these entries mean (and there are far more than pictured), and it would seem to indicate that there are many, many states for the device to be in. During testing, I observed only 5 conditions logged.

From my examination of the logged entries, light_idle_to appears to be how long the device has to be left alone before it enters “light idle” mode. If this entry appears after “normal” mode, it indicates the device has not been used for (for this phone) 5 minutes. But “not in use” and “normal” need understanding too. If there are no restrictions on power or processes, this is “normal”. Charging a device allows the phone not to restrict power usage to preserve the battery – it’s charging – so a charging device will show as “normal” and not “deep-idle” in this log.

The “deep idle” mode appears to be set by the simple idle_to flag, which is set to 1 hour on my phone. But “deep idle” mode is not activated 1 hour after “light idle” mode is activated – other checks need to be made. A project I found for editing timing explains it best,but it effectively cascades down a checklist with specific timers. You can say that a device has not been used for at least 1 hour (or as listed in the dump) if it entered “deep idle” mode.

Sensor

I have included this one on the off-chance it captures massive accelerations. However, raising the phone up from a table to look at it, for example, will register with the service, likely wiping more historic data. This could be fantastic data for collision investigations, if it manages to actually capture the collision event.

In terms of interpreting sensors, the accelerometer is probably the most viable in providing this data. It records linear accelerations in the classic x, y, and z planes, and it records it in the standard meters per second per second. A stationary accelerometer on a flat surface should register 0ms-2 in 2 planes, and 9.81ms-2 in the remaining plane, usually the z plane. A negative deviation from 9.81 in the z axis implies acceleration in the same direction, i.e. the phone is moving downwards, and a positive deviation means acceleration away from the gravity source.

Powercontrol

Similar to deviceidle, this tracks inactivity. It has more historic data, but only seems to record events such as overnight when a phone is charging. It lists these as “idle” events, but seems to have a different definition to those in deviceidle. In examining this log for my own phone, it is quite obvious what my shift pattern has been for the past 2 months.

Telecom

I think this is fairly self-explanatory – it logs calls in high detail. Sadly, phone numbers are blocked out.

Usagestats

Very useful for recent, second-by-second user activity, like with batterystats. This, however, records which activity was launched and not just just the calling app. To use WhatsApp as an example again, we can tell if a user opened the contacts, settings, or conversation views.

[...] package=com.whatsapp class=com.whatsapp.Conversation

Some difficulty arises if we assume “Last Time Seen” refers to the device user using an app. I encountered several instances where this did not reflect real activity. Slightly changing the scope from “seen” to “used” produces more accurate results, so this is what I’ve gone with in my script.

Also, there seems to a bit of bounce when switching between activities, in that the new activity may be triggered before the previous activity has completed its pause/stop task. This can’t really be coded for without adding more invisible interpretation to the data – I think it best to leave it minimally processed, timestamped as-is, and remember this bounce when examining this log.

Quick Fire Round

This is not an exhaustive list of services, and different vendors might have their own services too, but these are a few that at first glance appear forensically useful but actually mostly aren’t.

  • Alarm – internal job chronometer, not the kind that wakes you up in the morning
  • Connectivity – tethering.
  • Content – app syncs to Google account.
  • Display – framerate, brightness, and other display properties.
  • Dropbox (if installed) – lots of automatic keymaster events. No mention of Zuul.
  • Fingerprint – single line JSON with number of fingerprint uses since boot maybe.
  • Input – detailed touchscreen information.
  • Input_method – lists a few screen touch events (no locations) but likely overwritten by the time Developer Options are enabled during examination.
  • Location – mostly satellite information.
  • Mount – what you’d expect; the emulated sdcard partition and any real SD cards.
  • Netpolicy –may be useful in fringe cases, it keeps a very short log of firewall checks.
  • Netstats – no timestamps or app details.
  • Network_stack – validation and possibly video casting logs, no app info.
  • Secrecy – pretty much just phone IMEI, and no activity relevant to this work.
  • Shortcut – no activity, but interesting that it has apps’ popup menus, and (for communication apps) can give you contact names/numbers if they’re a pinned or frequent contact.
  • Storaged – app and process sizes in storage and memory, no logs.
  • Trust – logs agents such as location-based and connected-MAC unlocking.
  • Wifiscanner – very useful when looking for WiFi networks seen on last scan (my phone logged 34 networks with SSID, BBSID, security, and signal strength), but not useful for this work.

Closing Remarks

Hopefully if you’ve made it this far, you see the benefits of grabbing this data and analysing it as soon as possible after time-sensitive incidents. My example focused on a traffic collision, but could be equally useful in piecing together the activity of a vulnerable person currently Missing From Home. The script I’ve written is effectively a collection of parsers as one monolithic script. Coming in at 450 lines, I’d possibly call it a megalith of a script. Currently, it outputs the parsed data to a text file, which can be loaded into other software and parsed – I made a decision not to output all dumps to their own file, but this is easily amendable for your own need. Since my script produces a list with a datetime object in it before writing to file, you could take a copy of my code and wrap it in a function to be called by whatever other tools or scripts you are running. For example, it should be fairly simple to use this in conjunction with Cellebrite’s Physical Analyzer and add all of these newly captured events into an existing timeline.

If you want to use my script but don’t want to scroll all the way back up, here’s the link again. If you want to start exploring services yourself, you can start by running “adb shell service list” to get all running services on a device, then “adb shell dumpsys [service]” to get the output. If you have any comments, I’ve left comments open below, or I can be contacted on LinkedIn.

References & Reading

Leave a comment