Locations, Locations, Locations
Ian Whiffin
Posted: 18th July 2020
Revised: 22nd July 2020

Even though iOS Location Services has been around for a number of years now, there still seems to be some confusion about how and why it does what it does and how reliable the data is. I have testified in court a few times in relation to the data obtained from Location Services but since I recently incorporated this type of data into ArtEx, I thought now was a good time to do a really in-depth study of this technology.

This is a large post, but rather than break it up into smaller pieces, I thought I'd just segment it instead. Please bear with it and click the buttons to reveal additional information.

Also please note that I am not an expert in the mathematics required to calculate location information. What I am presenting in parts of this blog is simplified data to the best of my understanding as a result of research I have done. If you see anything that is incorrect please do not hesitate in contacting me and I will make the required changes. Ultimately, this post is about Location Services, but I couldn't write it without going over some other aspects of how it works.

To make this a little easier, I've also made this into 2 PDF documents for easier printing. The download links are available at the bottom of the page.

Assisted-GPS (A-GPS)

To my knowledge, all Smart Phones are Assisted-GPS devices (A-GPS) rather than straight GPS devices like in-car Sat-Nav systems are.

"Assisted-GPS" is the term used for the collection of technologies used by devices to determine their location.


Using Satellite GPS is the most accurate method for determining location but is not always practical (as described later), therefore other technologies already built into smart phones can be employed instead. Each technique has its own pros and con’s. An overview of each technology is shown below:

Select from the options below
Cell Siting WiFi Crowd Sourcing GPS

 

Before you continue, I don't want you to miss out on the rest of the information in the Cell Siting, WiFi Crowd Sourcing and GPS sections. This is a reminder that you may want to scroll back to the top and move to the next section.

iOS Location Services

iOS comes with an API known as 'Location Services' for easily requesting the device location from the device.

Developers can specify how accurate they need the location information to be. This means that applications that just need a general area can ask for low accuracy data (a city or area for example) but applications that require more accuracy such as navigation services can request the higher accuracy; striking a balance between speed and accuracy as the app dictates.

Prior to iOS8, a "Significant" change in location meant when a device changes from one cell area to another and for the most part that was fine. But when iOS8 came out, Location Services had been overhauled to include Geo-Fencing services. It's what allows location based reminders such as "Hey Siri, Remind me to do X when I leave work".

Using Geo-Fences meant that it needed to be much more accurate that cell tower locations would allow and so WiFi crowd sourcing became a norm. It makes sense, because as mentioned above, WiFi networks are already being scanned anyway to find a network to connect to. Monitoring it for significant location changes is a small amount of extra programming. Basically, the device keeps track of your location and once you have moved a significant distance, it checks to see if there is a Geo-Fence setup for either the area you have entered or the area you have left and responds appropriately.

The iOS device has a large quantity of locations and WiFi networks stored locally in Cache.sqlite and threebars.sqlite (and possibly elsewhere too) so it is able to resolve locations from WiFi networks without even needing an internet connection. This list of networks appears to refresh every so often in order to keep up-to-date.

iOS Frequent and Cached Locations

Now that we've covered the basics of how devices obtain their location, I'd like to take a closer look at when devices get their location data.

I'm sure that most people are familiar with "Frequent Locations" but for the sake of completeness I will describe it again.

The idea is that every time a device visits a location a record is kept that the device was there from time A to time B. When the device returns to that same location again, a second record is created and therefore the tally of "total visits" to that location increases.

Eventually, when the device has returned to the same location enough times, it is considered a "Frequent Location". If you have an iPhone, you can check yourself what your Frequent Locations are by going to Settings > Privacy > Location Services > System Services > Significant Locations (Note the additional security requirement at this stage; this is why this data only appears on a Full FileSystem extraction).

The actual algorithms that Apple use to determine what is and what is not a frequent location, or even when to record a location visit in the cache are not documented anywhere. I have done exhaustive testing to try to help answer these questions...

Real World Testing

I have an iPhone 6 running iOS12.4.1 which I use for testing. It doesn't have a SIM card and only has a WiFi connection when I'm at home. I placed this phone in the centre console of my car as I drove around the city. The phone was never even touched for the entirety of the journeys. It's also worth noting that this was the first time I'd taken this device to any of these locations.

I extracted the phone several times a day to monitor the changes and plotted out some of my journeys using ArtEx..

Over the course of several days (16th June to 23rd June), with minimal usage of the device, it still cached over 7,000 location records in com.apple.routined/Cache.sqlite database..

There was generally a noteable difference on the daily plots depending on how much traveling had been done.

Date Activity Total records for day Average/Hour
16th June Home > Work > Home 1231 ~51
17th June Home > Work > Home 997 ~42
18th June Home > Work 370 ~15
19th June Work > Shop > Home 684 ~29
20th June 3 hour drive around city. 1645 ~69
21st June 4 hour drive around city. 1232 ~51
22nd June No journey 890 ~37

Notes:
Although the drive around the city on the 20th was approximately the same duration as the drive on the 21st, there was more time spent parked.
Although the 22nd was spent at home, the phone was being constantly moved around between rooms.

So as you can see, with virtually no usage of the device, it was still recording my location on average 42 times every hour, with increased frequency when in motion.

As for what causes the location to be recorded? I'm still not entirely sure. But remember that paragraph from Apples website from earlier that I told you to remember? In particular the bit that says:

" If you're traveling (for example, in a car) and Location Services is on, a GPS-enabled iOS device will also periodically send GPS locations, travel speed, and barometric pressure information to Apple to be used for building up Apple's crowd-sourced road-traffic and indoor pressure databases."

At random(?) times, iOS will just get a GPS fix and send that data to Apple. Awesome as that should mean even better location information that with WiFi Crowd Sourcing.

The time difference between records is sporadic at best; with gaps being anywhere between a single second and 20 minutes or more.

I am of the opinion that the sporadic nature of the data is a result of several things;

a) Being in a location with no/weak WiFi networks - As the location is determined by scanning for local WiFi networks, it stands to reason that no networks means no location data.
b) Unrecognized WiFi networks - maybe the networks that are being seen by the device aren't in the devices location database?
c) As stated, it's just periodic in order to update the Apple servers.

**Update : A complete oversight on my part is that as pointed out above, by test device does not have a SIM card installed. I decided to take a look at my real device and found that some of the cached locations were a 1000m+. This is clearly too large for a WiFi network so left me thinking that either the source WiFi data is inaccurate (unlikely as I would have probably observed the same low accuracy reading on my test phone) or that Cell Tower locations can be used too. I'm guess that switching between Cell Towers causes a location to be recorded but this is a little difficult to test. It's certainly good to bear in mind though and can account for some way-out accuracies.

 

Accuracy

The cache.sqlite database includes "Horizontal Accuracy" as a field which is a value in metres. Basically, it is an indicator of how accurate the phone believes the GPS co-ordinates to be.

ArtEx uses the Latitude and Longitude to plot the location on a map and draws an approximate radius around it using the "HorizontalAccuracy" information. The maps created by ArtEx look like this:

For anyone who hasn't used ArtEx, I should mention that it only draws maps when the Horizontal Accuracy is under 100m. This is simply to save on processing/memory and to make it easier to home in on the most accurate location data.

After plotting the map information for my journeys, I manually went though all of the created maps and verified their accuracy, including verifying the accuracy of the locations that were not plotted to maps.

Click on the links below to see a breakdown of the journeys in this case study
Journey 1 Journey 2

The upgrade to "Frequent Location"

So now we have an idea of how often locations are saved in the Cache database and how accurate they are. But what flips the status from simply a location that was visited to one that is designated a "Frequent Location"?

Let's start by taking a look at the tables found in Local.sqlite and Cloud.sqlite (Both very similar content but as the names suggest, one is local on the device and one is designed to be sent to the cloud).

The three tables I'm interested in right now are:

ZRTLEARNEDLOCATIONOFINTERESTMO

ZRTLEARNEDLOCATIONOFINTERESTTRANSITIONMO

ZRTLEARNEDLOCATIONOFINTERESTVISITMO

Firstly, ZRTLEARNEDLOCATIONOFINTERESTMO is a list of the device's Frequent Locations. Of note, it includes ZLOCATIONLATITUDE, ZLOCATIONLONGITUDE, ZDATAPOINTCOUNT, ZPLACECREATIONDATE and ZPLACEEXPIRATIONDATE but it does not include any information about when they were actually visited.

I noticed that of the 6 locations, all had the same expiry date and the creation dates were not unique either.

You can see that records 1 and 2 share a Creation Date, as do records 4, 5 and 6 (well, within a few seconds anyway).

This means that the Frequent Location record in this table cannot possibly be made at the time a location is revisited and thus must happen afterwards, during a single process that works out all visits and creates the appropriate frequent location records in this table.

I typically found that this process ran every 2 to 4 days but don't quote me on that. There really wasn't any discernable pattern. I expected maybe every X days or every X records but neither seemed to be right.

The table ZRTLEARNEDLOCATIONOFINTERESTTRANSITIONMO relates to the movement between locations; You may have noticed on your own phone when reading Frequent Locations it often says something to the effect of "Arrived via a 10 min. drive". This table is how it knows that you drove and how long it took.

The ZLOCATIONOFINTEREST field relates to the Z_PK on the ZRTLEARNEDLOCATIONOFINTERESTMO table.

Again we have Creation and Expiry Dates, but now we also have ZSTARTDATE and ZSTOPDATE which relate to the journey to the frequent location. This table also has a field ZPREDOMINANTMOTIONACTIVITYTYPE which is the mode of travel. 4 appears to be car whereas 1 appears to be walking.

ZRTLEARNEDLOCATIONOFINTERESTMO is a log of the time actually spent at the defined Frequent Locations.

Again you can see that a lot of records share the same creation date, suggesting that a block process creates these records at the same time.

You can see that there are:
3 records at 2020/06/10 at 07:38:10 (Green)
3 records at 2020/06/10 at 11:22:41 (Yellow)
2 records at 2020/06/17 at 06:59:56 (Pink)
2 records at 2020/06/18 at 07:45:05 (Orange)
6 records at 2020/06/22 at 18:36:31 (Red)

You will also notice that the creation dates are not in date order (It's ordered by the Z_PK field) and the CreationDates are also incredibly similar to the PlaceCreationDates of the ZRTLEARNEDLOCATIONOFINTERESTMO table.

So we can assume that there is a process that runs every few days that determines which locations have been visited enough to upgrade them to "Frequent Locations". The presentation below goes into a little more detail about how this probably works.

Interestingly, in the Cloud.sqlite database is a table called ZRTADDRESSMO which is the resolved address for each of the Frequent Location records. This includes Locality, City, Road, Area of Interest etc.. But this table is not found in Local.sqlite.

 

Note for testing : The records are created once a condition has ended. For example, the Frequent Location Visit record is only recorded in the database once I leave the location. Don't do test extractions expecting to see when you arrived at home/office if you are still there. Likewise if you were imaging a device at the scene, you will not get the time the device arrived there.

 

 

This presentation demonstrates the creation of cached locations and the upgrade to "Frequent Location" status.

Reset Play Slide 0/0

 

Now we've seen how the cached records are distilled into Frequent Locations, we can see that it actually doesn't matter how many times you visit a location. What matters is how many records there are to show you in that location. Records are created somewhat randomly (at least that may be how they appear), and if you're there long enough, there may be enough records during a single visit to qualify as a Frequent Location.

In my testing, I had a Frequent Location record with just 38 DataPoints; a location I only visited once but spend an hour at walking around.

 

We should also define what a Frequent Location is in terms of area.

Obviously, to be useful in knowing when I'm at "Home" or "Work" or wherever, it's no good to have a specific Lat/Long coordinate. For example, I want my phone to know I'm at Home regardless if I'm pulling onto my driveway or at the far reaches of my backyard. For my Work address, the area may be even larger. So there must be some tolerance.

My testing has shown that once i am around 80m from my home address, my phone registers that I've now left that Frequent Location. I tested this by slowly moving away from the house and stopping frequently for a set amount of time. Once I extracted the phone, I knew how far away from my house I was at the time the "Exit" event occurred.

As this has been consistent at around 80m, I don't believe this is the result of a coincidence that my phone decided to create a record at that time and I instead believe that this is directly related to my phone leaving the WiFi range of my home network triggering a location check.

Of course, 80m is a fairly massive area...

The good thing about this is that just being close to a frequent location is probably enough to keep the record of it (instead of losing it as a purged cache record). The downside is that if you need highly accurate data, it may not be good enough.

Vehicle Events

Another location artifact of note is the vehicle event locations stored in ~/private/var/mobile/Library/Caches/com.apple.routined/local.sqlite. This appears to be somewhat related to the bluetooth connection information found in KnowledgeC.

The idea is that when I'm in my car, my phone is connected via Bluetooth. Once I stop driving and turn the car off, the bluetooth connection ends and a vehicle event of "Parked Car" is created.

In practice, I've found it to be cleverer than it sounds.

I conducted several tests with different variables:

While in motion, Bluetooth turned off on the phone: No vehicle event was recorded.

While in motion, Bluetooth turned off on the car stereo: No vehicle event was recorded.

Drive to location A, turn engine off and leave the phone static in the car for ~25 minutes: No vehicle event was recorded.

Drive to location A, turn engine off and walk away from the car with the phone: vehicle event created before I was even 100m away from the car.

 

I have tested these scenarios multiple times, with a few variables such as with/without network connectivity etc. and it appears pretty consistent that is the combination of Bluetooth Disconnection followed by walking that causes the phone to realise you have gotten out of the car and therefore create the Parked Car event.

This was important for a case I was working where I was able to correlate the bluetooth connection/disconnection events of a device to frequent location events.

The thought process was that when the bluetooth connects, it was because the engine started and a journey (ie. a Exit Frequent Location in this case) was anticipated.

Entering a Frequent Location (ie arriving home) would precede a Bluetooth Disconnection as the user arrived home and exited the car.

The issue was that there were bluetooth disconnection and reconnection event with no associated Frequent Location information. This suggested the user parked the car briefly but there was absolutely no Vehicle Park events for the day in question.

My determination was that the phone never left the car, hence a park event was never recorded. The time of the bluetooth disconnection/connection was extremely relevant and showed that *something* occurred at that time. This hypothesis was later supported by additional evidence found soon after..

Update : As pointed out by Josh Hickman (@josh_hickman1 / thebinaryhick.blog), CarPlay also appears to create Vehicle Events. Alas, my car does not have CarPlay so I am unable to test. And the last time I drove a CarPlay vehicle was well over the 2 months that the vehicle events appear to be stored for.

Looking at the Extraction of Josh's phone that was made available in May, there are zero bluetooth events related to a vehicle and 82 vehicle events. Although closer inspection shows that there were numerous duplicates and only 5 unique events.

 

WiFi Access Points

Also in the Cache.sqlite database is a table called ZWIFIACCESSPOINTMO which contains thousands of records, each with RSSI, Date and MAC address (Amongst other things).

Before you get all excited at finding this treasure trove of location data, you should notice that the dates are very... same-y. It appears that this is (one of) the tables used by the device to assist with determining locations and is not a list of where the device had visited.

The ZFINGERPRINT field appears to relate to the ZRTFINGERPRINTMO table but that's as far as I've looked into it. It can't be used to determine the devices location at any given time so I've not investigated any further at this time.

netusage.db

Finally, it would be remiss of me to write an article about iOS Cell Siting and Location Services without mentioning netusage.db.

netusage.db can be found in ~/private/var/networkd/netusage.db and contains a table called ZNETWORKATTACHMENT.

This table keeps track of all cell towers connected to; but it only keeps the FIRST and LAST DATE the connection is made.

For example; My phone connects to tower A for the first time. A record is created with the Tower ID and today's date as both the FIRST and LAST connected dates.

When I connect to that tower again the day after, the existing record is updated with a new LAST connected date.

It's not great, but I used it (in absence of much other location data) to prove that a device had left the city and headed west, contradicting the suspect's story. Without going into too much detail, the device had numerous cell tower connection records that all showed a FIRST connection date of the date of the offence and I used their order of creation in the database to work out a rough direction of travel.

Of course, this was only really helpful because the distances involved were way too much to be the result of network handoff. The truly beautiful thing was that the cell tower connections pretty much matched the connections of my victim's device; for whom we also had Cached Location data which confirmed the location data obtained from the cell tower connections.

 

Wrapping Up

Thank you for sticking with this until the end. I realise it's a big topic but hopefully my research has answered some questions you may have had or will make life easier for you in the future.

Location Services is something that the majority of people know exists, but there are so many questions remaining.

Overall, I'd say it is very reliable with only a few anomalous records which still aren't bad, just not perfect. (Just remember to take into account the Horizontal Accuracy information).

You'll need to access a FULL filesystem extraction (passcode must be known) in order to get the location data and the cache is typically wiped after 7 days so bear that in mind too.

My rule of thumb is that if the phone says it was there, it was. Or it was at least close. BUT, if it doesn't say it was there it does not mean that it wasn't there. It just means that a record wasn't created.

Remember, you can download my iOS Usage Visualization tool "ArtEx" for FREE from the 'Software' section of my site which maps out Location data from Cache, Frequent Locations, Cell Towers, Media, Apple Pay and Vehicle Events.

Download Links - Sorry for making you scroll to the bottom to get these. But I wanted to give you the opportunity to view it in the browser first. :) - PDF 1 | PDF 2



< Previous Blog Article No More Articles... Yet
"Favicons"