What I learned from Lint today

An auto-backup rabbit whole.

Bob Dahlberg
Level Up Coding

--

Today I got forced to learn a bit about auto backup. And I always enjoy learning. But this time, I would’ve appreciated more concrete answers. Hopefully, my findings will help someone else faster.

I created a new android application from Android Studio, “No Activity”-template. Just after creation, I ran the script ./gradlew lint on it; 1 warning.

On SDK version 23 and up, your app data will be automatically backed up and restored on app install. Consider adding the attribute android:fullBackupContent to specify an @xml resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html

The lint warning is actually excellent. Very descriptive and specific. And what’s even better, is that in my real project, where I use GCM I get the following warning which is even more spot-on:

On SDK version 23 and up, your app data will be automatically backed up, and restored on app install. Your GCM regid will not work across restores, so you must ensure that it is excluded from the back-up set. Use the attribute android:fullBackupContent to specify an @xml resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html

The documentation on auto-backup is also a good read that I recommend every developer to read. You should know what data you store and let other systems store. It might include sensitive data.

It all seems very good so far, and the only minor issue is that you start with a warning. However, there’s a but, and it’s specific to when you use push notification. The lint warning tells us that the GCM regid will not work across restores. And that we must exclude it from our backup set. And we should know from the documentation how to exclude a file from backup. But which file?

What’s even more irritating is that there’s a quick fix for Android Studio to solve the lint-warning. Creating the backup resource file, and in that autogenerated XML-file, there’s a comment saying:

<!-- Exclude specific shared preferences that contain GCM registration Id -->

I’d love to if I’d known which file to exclude! At least I now know it’s in shared preferences. I also know from the documentation on auto-backup that;

If you want your app to save its state, store state in Shared Preferences and recover Shared Preferences on restore.

So my problem now is to solve which files to exclude and which to include from shared preferences. Since I’d love to benefit from the auto-backup, I’d prefer only to exclude the file, containing the GCM id. But my searches haven’t given me any concrete answer. So I figured to look at the device in Device File Explorer in Android Studio and see what files there are. And this is my second recommendation to all, do it. There’s a lot of juicy bits in there when using third party libraries.

At least now I have a qualified guess that the id referred to is stored in the shared preferences file named com.google.android.gms.appid.xml, and googling it and looking at its content seem to verify that it is it. But I haven’t seen any official note on it. I also have a file in the no-backup folder named com.google.android.gms.appid-no-backup. If the id shouldn’t be backed up, shouldn’t it be stored in there from the start?

Anyway, with this new knowledge of whats dwelling in my shared preference folder from different dependencies I use I feel that I only want to include my own files. And would love to have a pattern for that saying include all se.challenge.*.xml and then I can use that pattern when creating shared preferences in my app. But unfortunately, you can’t use pattern-matching in the full-backup content resource. The only thing except for full file names is the “.” specifying the entire folder, and it also includes all subfolders. But shared preferences don’t use folders so it doesn’t help me either.

So as of today, my only solution is to specify each and every file I use in shared preferences, that’s not a problem. The problem is to remember every time I, or someone else, adds a new shared preference to add it to the backup too. On the upside, it’s a secure way of not backing up data unintentionally.

My main takeaways on specifying rules for auto backup

  • Android includes by default almost every file in the app. But as soon as you insert an include-tag into the XML, you override that, to only include what is specified. (And it spans even over domains).
  • When calculating what to backup the system will aggregate all includes, minus all exclude’s. So exclude always takes precedence.
  • You can specify for five different domains; “file”, “database”, “sharedpref”, “external”, and “root”.

And as the last guide, this is the ruleset that comes as default:

<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include domain="file" path="." />
<include domain="database" path="." />
<include domain="sharedpref" path="." />
<include domain="external" path="." />
<include domain="root" path="." />
</full-backup-content>

So if you only want to change the rules for shared preferences, and as in my example only include one file, you still need to add the includes for the other domains. Otherwise, they will be excluded.

Full documentation on how to write the XML can be found here: https://developer.android.com/guide/topics/data/autobackup#XMLSyntax

Final thoughts

Backing up settings, state, and prefs is a powerful and often forgotten feature in Android. The shift towards auto-backup made it happen in the background but with some concerns. Make sure you know what to back up, and it can bring some magic to your users. But if you don’t know, you can create some security vulnerabilities.

PS. The reason for not keeping the GCM registration id is that if the old one is restored, it is used. And using an old ID that is meant for another device or another installation can cause unexpected behavior, such as not delivering push notifications.

--

--