Finally switching from iOS: My GrapheneOS setup

published on in category , Tags: android grapheneos foss

It’s been more than 10 years for me writing about self-hosted infrastructure and systems that care about privacy, yet I have kept using Apple Smartphones for this whole time. While I always liked the idea of Android being fundamentally open source (as the AOSP), neither the hardware that it ran on nor the inevitable dependency on proprietary services from Google, a company that reportedly does not care about your privacy, were appealing to me. And while it was always possible to run Android completely free of Google Services, in practice it’s way harder given that most of our surroundings in the tech space are proprietary products (that oftentimes don’t care about the few people that don’t want Google Play Services). Plus, from a security perspective, running dubious custom ROMs from the xda-developer forums is a nightmare to begin with, most Android apps look horrible etc. :) It’s hard to say I’m a real fan.

Luckily, most of that changed: Throughout the last months I’ve found a mobile setup based on open source Android that works great for me, runs on beautiful and performant hardware and keeps the dependency on Google Services at a minimum. By now, I’m running this setup as a daily driver for a few months and don’t feel like switching back. In this following post, I will describe what my setup looks like and how I’m using it.

Introducing GrapheneOS

GrapheneOS is a security focused AOSP based operating system. It hardens the upstream Android project with many changes already incorporated into Android itself. Besides that, it’s a stock and minimalist Android OS with a few extra utilities.

Additionally, GrapheneOS tracks AOSP relatively closely, so it’s easy to stay up-to-date with the newest Android developments. While there are other similar projects like Calyx, the way GrapheneOS is focused is most appealing to me.

Additional permissions

One of the biggest benefits I get from GrapheneOS is the additional toggle of permissions compared to AOSP: Network (as in “all network connectivity”), and Sensors (misc. sensors not possible to enable/disable separately). Restricting network access for some apps is a big deal and while I get that Google does not want that in stock Android, it’s a big deal because it allows me to run some Google apps in an at least somewhat privacy-friendly way.

Having this is both a blessing and a curse, however: Google’s SafetyNet is an attestation service to check the integrity and certification status of the OS. Since having those extra toggles is against Googles Certification Checklist, GrapheneOS only passes the basicIntegrity check, which is the weaker of the two. To also pass the ctsProfileMatch check, the OS would need to be certified by Google, which is apparently not happening and could lead to some apps refusing to start on the OS, although I have not encountered any. Apparently, some US banking apps and games don’t work because of that, alongside Google Pay.

Storage scopes

Storage scopes are similar to what iOS does in terms of restricting file system access to apps. Ever noticed that apps upon the first access to your image gallery will ask you whether you want to allow access to all images or only specific ones? Storage spaces is a similar feature but for the whole file system. Instead of only granting or denying an app permissions to the full file system, in GrapheneOS you can define which scope an app is allowed to see. This is completely transparent to the app itself. It just looks like all files that you don’t grant permissions on, are simply not there.

Sandboxed Play Services

In contrast to efforts like microG, which provides open-source, reverse-engineered alternatives to the Google Play APIs (but still uses Google services in the backend), GrapheneOS runs the actual Google Play Service closed-source binaries, but manages to run them within the usual Android App Sandbox. This is in stark contrast to stock Android, where the Play Services and Google Services Framework run with higher privileges, which allows them to be so privacy invasive.

On GrapheneOS instead, you have all the normal permission toggles for Play Services and GSF, which allows you to restrict permissions on location, notifications, storage etc., and even on network (although that might not make too much sense depending on your usage).

Getting rid of Google with a Pixel

While it sounds a bit weird to use a Google Pixel phone when the motivation is to get as far away from Google as possible, it actually makes a lot of sense:

Since the Pixel phones are what previously were known as reference phones for other Android developers, Google does not sacrifice openness on their phones. That means that Pixels allow the installation of third party operating systems in a somewhat official way, alongside with full verified boot support with custom keys. That fact alongside other security-related features makes Pixel phones effectively the only option for the GrapheneOS project to run on.

My setup

I run GrapheneOS on a Pixel 7 Pro. With Material You icons (beta) enabled, I was able to come up with a visually pleasing and lightweight home screen. A full list of the apps I run, including some configuration details can be found below.

When I set up the phone initially, it was relatively much effort compared to setting up an iOS device. But after finishing the setup of all my apps, synchronization of Files, Calendars, Contacts etc., everything runs smoothly and mostly without decreased usability compared to iOS on a day-to-day basis. That said, for me, it was hard to find a setup of apps and services that works seamlessly and does not have sub-par usability.

In general, I strive for a minimalist, close-to-stock look and feel on the device: No apps that are not needed, clean user interface with Material You enabled whereever possible to get a cohesive system.

UI scaling horror

When I was test-driving my migration to Android, I rented a Pixel 7 non-Pro device for a few months and set up everything like I would on my daily driver. When I then bought the Pixel 7 Pro, the biggest problem was the UI scaling. Since the screen is a bit bigger, the whole UI felt way too big, not offering any improvement in terms of screen real estate. I consider the native and virtual resolution choices on this phone very questionable. With the default scaling everything is too big, with the smaller UI scaling everything is too small (and less sharp, like on MacBooks with scaling set to “more content”). Eventually, I settled with the smaller UI scaling and got used to it somewhat quickly.

Nevertheless, coming from the non-pro, the UI scaling is worse, which I hope will be changed in future hardware revisions. Get the non-pro instead, it’s cheaper anyway and the camera is not such a big difference ;-)

No profiles

Even though I generally try to stay away from Google Apps as far as possible, I decided to install Sandboxed Play Services in my main profile. The reason is simple: I run a few apps that need GSF, and I don’t feel like switching the profile every time I access them. The main reason is the delivery of Push Notifications. I know there are apps like Insular that allows segregation of private/work apps within a single profile, but I didn’t check that too detailed yet. Instead, I revoked all permissions from Google Play and Google Services Framework except for network access, since this is needed for push notification delivery. That said, I’m not signed in into a Google account on my phone at all and Google Play cannot access my location, file system or any other sensors, so I guess I’m okay.

Local & Push notifications

Since I’m self-hosting most of the services I use on my phone, there are at least some cases where I manage to bypass Google Play Services for push notification delivery. Unfortunately, this dependency is really hard to get rid of: Since the backends of the services we use day-to-day directly connect to Google servers to push notifications, there’s no way to provide a drop-in-replacement for that kind of infrastructure. You’re basically relying on the mercy of the app developer to provide notifications locally. In that scenario, the app has permissions to persistently run a background process (which you might have seen already because they are forced by the OS to display a persistent notification) that maintains a TCP connection to the service. This already sounds expensive from a networking and energy perspective, and it is. The process in the background, which, to make things more complicated, is called a foreground process in Android (wtf?), needs to aggressively run healthchecks and send heartbeat signals to keep the connection alive, especially when running on cellular having varying network connectivity. The server then can use the active connection to push messages to the client, which in turn can use the local notification API in Android to show a notification.

This is where central push notification infrastructure really shines. It basically does the same, but proxies requests for all apps, which makes battery drain negligible. There’s no widely implemented alternative push notification service available yet, although projects like Gotify try.

Luckily, local notifications can be also sent when tasks are executed periodically. When you think about it, there’s really only a few occasions that you actually need real-time push notifications.

A list of apps that I run and how I configured notifications can be found below.

Material You

Material You is a framework created as part of Android 12, which allows apps that are using Material styles to adapt their UI and icons to the overall color scheme of the OS. I love that because Material and Material You try to solve one of my biggest turn-offs when it comes to Android: The UI of most apps is sub-par to iOS apps, and most of the time not by a small margin. Many apps still don’t support Material and Material You, but in selecting my day-to-day apps, I try to favor ones that use those frameworks.

App store nightmares

You can love it or hate it, but a central app store goes a long way when it comes to comfort and security: Apps can only be provided by registered developers, are sometimes somewhat audited and with that provide a “trusted” place to get the apps for the device holding your most personal data. However, when it comes to privacy, the audits don’t go a long way: Alternative Play Store frontends like Aurora Store hold reports for trackers found in apps provided on Google Play. Reviewing them reveals how big the problem actually is, and there is only so much you can do about it. Sure, you can try to block access to trackers using filtering VPNs and restrict access to the apps, but there’s no ultimate solution to this problem. And with the goal of removing Google dependencies as much as possible, it’s hard to use the Play Store.

F-Droid is another popular alternative app store that distributes open source software and requires apps to be free of proprietary services and trackers. For that reason, F-Droid reviews apps and builds them on their own. And while this results in pristine and tracker-free apps that you can trust if you trust the F-Droid project itself, it does not come without problems: Since the app signing happens on the F-Droid side, all apps are signed with the same key, and it’s not the key of the developers. That effectively bypasses a basic Android security feature. When an app is first launched, the signature is pinned and subsequent app updates are only allowed if the signature matches. With F-Droid signing the apps on their own, you basically have to rely on the F-Droid team to not sign any malicious code, because if so, the device will simply install and execute it. The signing infrastructure on F-Droid is apparently air gapped, which would make an online attack impossible, but you probably don’t have to think twice to come up with a supply chain attack taking place before the actual signage, and suddenly it would be solely up to people reviewing code to figure out if it was tampered with. Sure, this can also happen even earlier in the repositories of the developers themselves, but then you would at least have only one app with malicious code and not the chance of multiple infected apps that were installed from F-Droid.

At the same time, I have a hard time understanding people bashing F-Droid for that model. It has lots of advantages, too. In the end, you have to understand the impact of those fundamentally different designs and choose the one that works best for you.

For me, it’s a mixture of everything: I use Obtainium (for the most part) and Aurora Store (for the few proprietary apps I depend on) to keep my apps up to date. Within Obtainium, I source many apps from F-Droid, mainly because of their requirements for apps to not include proprietary services. Other apps, where I feel I want to get updates faster, and I trust the developers in general, I fetch apps directly from GitHub or their homepage. This works for some proprietary apps as well, if they publish the APK on their site. That allows me to rely on the signing-based security features for the most part while for apps where I feel it’s needed, I can grab the F-Droid build instead of the main distributable.

App list

Here’s a rough list of the apps that I use (incomplete) including necessary details and the original app that I switch from or you would usually switch from on iOS:

iOS App Android App Type Plans to replace Notes
Apple Podcasts AntennaPod Open source No awesome!
Apple Books audiobookshelf Open source No with self-hosted backend service my audiobooks
App Store Aurora Store Open source No install proprietary apps and update them
iCloud Keychain Bitwarden Open source No self-hosted Vaultwarden backend
CAPod Open source No AirPods Pro battery stats as notification
Apple Wallet Catima Open source No Store cards
DAVx5 Open source No Backend to sync CalDAV and CardDAV, iOS has that built-in
iCloud Drive Synology Drive Proprietary Yes Being replaced some time, for now it’s fine
Calendar Etar Open source No
Mobile Safari Fennec Open source No F-Droid build of Firefox, with self-hosted sync server
Camera Roll Google Photos Proprietary Yes just not to have to use the ugly AOSP gallery, w/o network access, no sync or anything
Gboard Proprietary No only got network access for 1 min to sync the dictionary, now no permissions at all
Home Home Assistant Open source No
Apollo Infinity Open source No Reddit client
Apple Mail K-9 Mail Nightly Open source No w/ IMAP IDLE, persistent background process for push
Camera Google Camera Proprietary Yes only camera and location access, no network
Universal Clipboard KDE Connect Open source No sync almost everything with my Linux desktop
YouTube LibreTube Open source No
Apple Maps Google Maps Proprietary Yes nothing better so far for navigation, only network and location when used, not signed in
Ivory Mastodon Open source Yes Looking for a better alternative frontend
Reeder Nextcloud News Open source No
Notes Nextcloud Notes Open source No
Obtainium Open source No Install/manage most of the apps
(iCloud Photos) Synology Photos Proprietary No maybe switching to Immich as soon as it’s feature complete
Voice Memos Record You Open source No
Reminders Tasks Open source Yes Looking for something more lightweight
Weather Geometric Weather Open source No It’s so beautiful, best Weather app I’ve ever used

Conclusion

Overall, I’m pretty pleased with the setup. But given that I have spend quite some thoughts as you probably can tell by now, I feel I have a hard time appreciating the result. Did I nuke Google altogether? Unfortunately not and I could have replaced way more proprietary services, especially the Google ones. But with the current sandboxing setup, I feel good with the results. Data collection is probably down to an acceptable level and I don’t compromise on usability.

Now let’s just hope that none of the apps I use start requiring a strict SecureNet attestation (especially banking apps :)).

Bonus: Broken

I’ve never used phone covers or cases since it’s weird for me to spend much money on a nice and slim phone, just to put a case around it that makes it look like a brick. I never had a phone fall and break since I got my first smartphone. Look what happend three days after I got my Pixel 7 Pro: