My partner and I use GrapheneOS on our phones. Google is as supportive of this as you would imagine, so this causes some problems, like failing SafetyNet CTS preventing many bank and DRM’d media apps from working. She recently tried to use an app that seemed to refuse to launch because Graphene isn’t Play Protect Certified.
Google created a page to allow users of custom ROMs to register their Google Services Framework ID to bypass Play Protect certification requirements, presumably after some antitrust threats. There are reports that it originally accepted an IMEI as well, but that doesn’t seem to be the case anymore, even when padding it with zeroes.
So it seems like in theory we’ll be able to avoid some compatibility complaints on the Play Store and in apps by registering our devices with the GSF IDs - but first we need to find them.
android_id
, it is not the same as Settings.Secure.ANDROID_ID
(adb shell settings get secure android_id
) or the advertising IDs.
The GSF ID also changes when the device is wiped, and may be different for each
user.Official Method
On the device registration page Google recommends running:
adb root
adb shell 'sqlite3 /data/user/$(cmd activity get-current-user)/*/*/gservices.db \
"select * from main where name = \"android_id\";"'
This requires a debug build, which won’t help me on Graphene.
With su
The obvious workaround is to use su
to elevate to root, which is also not
helpful on Graphene, but may be for you. I also didn’t have sqlite3
on my
test device, so I did that part on the computer, and also fixed the quotes in
their query.
pc$ adb shell
phone$ su
phone# cp /data/user/$(cmd activity get-current-user)/*/*/gservices.db /sdcard/
phone# exit
phone$ exit
pc$ adb pull /sdcard/gservices.db
pc$ sqlite3 gservices.db "select * from main where name = 'android_id';"
The Internet’s Suggestions
For a long time, apps could retrieve the GSF ID. This was obviously a privacy nightmare, so they can’t anymore, and all apps that don’t use root are useless on Android 14ish and newer.
Without root
Since this ID is used to identify your device to Google, I suspected it would end up reused in some web interface. There were a few suspicious 16-character hex strings and long decimal numbers near my phone’s name in the source of the devices page of the Play Store, but none were my GSF ID. A different 21-digit decimal number shows up when selecting a device to install an app to, also not the needed ID. A base64 string shows up in other places, also unrelated.
Interestingly, I ended up finding it not on the Play Store but from the “Find Hub” device list.
To find yours:
- Load the Find Hub
- In Chrome, press Ctrl+Shift+J (Mac: Cmd+Opt+J), or in Firefox, Ctrl+Shift+K (Mac: Cmd+Opt+K)
- If prompted, type
allow pasting
. Don’t ignore the warning: Putting untrusted code here could give someone control of your Google account and more. - Now that you’ve ignored the warning, paste this incomprehensible mess into
the console and press enter:
window.AF_initDataKeys.map(k=>document.querySelector("script."+CSS.escape(k))).flatMap(s=>{t=s.text;return JSON.parse(t.substring(t.indexOf("(")+1,t.indexOf(")")).replaceAll(/({|, )([a-z])/g,'$1"$2').replaceAll(/([a-z])(:[ [])/g,'$1"$2').replaceAll("'",'"')).data[1].map(p=>p[4]+" ("+p[2][3]+" "+p[2][2]+") - "+p[0][0][0])}).forEach(p=>console.log(p))
- You should see a list of devices connected to your Google account, their models, and your GSF ID for each, which you can paste into the registration page.
Readable code:
// For each data key (e.g. "ds:0"), find its <script> tag
window.AF_initDataKeys.map(
key => document.querySelector(
"script." + CSS.escape(key)
)
).flatMap(
scriptTag => {
scriptText = scriptTag.text;
return JSON.parse(
scriptText
// Take just the {...} passed into AF_initDataCallback()
.substring(
scriptText.indexOf("(") + 1,
scriptText.indexOf(")")
)
// Insert quotes before keywords
.replaceAll(/({|, )([a-z])/g, '$1"$2')
.replaceAll(/([a-z])(:[ [])/g, '$1"$2')
// JSON requires double quotes
.replaceAll("'",'"')
).data[1]
// Make each phone's info info readable
.map(
ph => (
ph[4] // Name
+ " ("
+ ph[2][3] // Manufacturer
+ " "
+ ph[2][2] // Model
+ ") - "
+ ph[0][0][0] // GSF ID
))})
// And print the info
.forEach(
phone => console.log(phone)
)
Sorry for my javascript sins, it’s not a language I like much or know well.
Also sorry for the regex crimes in there - I couldn’t find the parsed data,
and Google disables eval()
with CSP.
If Google changes something and that code stops working, you may be able to load the Find Hub, press Ctrl+U (Mac Firefox: Cmd+U, Mac Chrome: Cmd+Opt+U), and search for your device name. There should be a 19-digit number near it.
Good luck, and don’t forget to write your congresscritters and demand better antitrust enforcement.