We have previously investigated the so-called “sampling coverage” of CAMS for Android 10. These tests showed back then a very good – 100% – sampling coverage – i.e., CAMS were collecting all the expected measures when running over a 24-hour period – also when the app was in the background.
With the release of Android 11 API level 30, a natural question arise – how does CAMS perform on Android 11?
This question is particular relevant for mobile sensing, since Google has introduced a number of privacy changes in Android 11, which impact the perfomance of background collection of sensor data, including:
- One-time permissions – Users can grant temporary access to location, microphone, and camera using one-time permissions
- Permissions auto-reset – If users haven’t interacted with an app for a few months on Android 11 or higher, the system auto-resets the app’s sensitive permissions
- Background location access – Android 11 changes how users can grant the background location permission to apps
- Foreground services – Android 11 changes how foreground services can access location, camera, and microphone data
So – pretty much the entire backbone of background sensing has been changed in Android 11….!
So we re-ran our tests and below are the results. However, before doing this, it was necessary to manually tell Android that the app (CARP Mobile Sensing) was allowed to access location “All of the time”, as shown in the screen shoot below:
Note that in Android 11 this cannot be set automatically by the app (via the manifest file). Google writes on this page that:
On Android 11 (API level 30) and higher […] the system dialog doesn’t include the Allow all the time option. Instead, users must enable background location on a settings page, as shown in figure 1.From the Google guide on “Request location permissions“.
And the guide continues to say that “you can help users navigate to this settings page by following best practices when requesting the background location permission.”
Below are the results of the test – divided into two parts: (i) running the app in the foreground and (ii) running the app in the background.
Figure 1 shows sampling from 16:08 in the afternoon to 08:00 the next morning. In this situation, the app was running constantly in the foreground. We see that we have a 100% sampling coverage, as with Android 10. All good so far… BUT.
Figure 2 shows what happened when the app was put in the background. This happened at 08:00 and the test ran until 18:00 in the evening.
We can observe a couple of things:
- When the app is put in the background, the sampling rate degrades and is no longer 100%.
- It seems to degrade over time – the initial sampling rate is 67% which gradually degrades down to 25%.
- When the app is brought into foreground again – which happened in the 14:00-15:00 timeslot – the sampling rate increase again.
At the time of writing, we do not have a solution to this. In general, it is becoming increasingly difficult to run background sensing continuously on Android. We will clearly look into it and see if things can be improved. But, we are off course limited to what is possible by the operating system.
But overall, however, we do think that the use of CAMS in creation of apps for data collection should comply with the privacy-enhancing recommendations from Google. Hence, data collection can take place when the user is using the app – e.g., as part of an AppTask.
As part of the testing, it was noted that the app was occasionally terminated. Of course, this could be due to a bug, but since the CAMS demo app has been running pretty stable in the foreground, this still seemed to (also) be caused by termination of the OS.
Hence, it is becoming increasingly important to design your app so that it can “survive” termination and gracefully resume operation (and sampling) when restarted.
For this reason, future versions of CAMS will look into how to make sampling more persistent. The
MarkedMeasure is one step i that direction. A marked measure persistently keeps track of when the measure was collected last time. It persistently marks the last time this measure was collected and provide this in the lastTime variable. This is useful for measures that want to collect data since last time it was collected. For example the
AppUsageMeasure. And it works across app restart.