Magisk module: systemize microG as a privileged system app so it can fill the Android framework network and fused location provider slots. Derives its privapp permission whitelist from the live device at install time.
  • Shell 67.7%
  • Nix 32.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
npilosov 91a4c3e128 feat: systemize microG as a privileged app for the location provider slots
Android binds the framework network location provider only to a system or
privileged app, and INSTALL_LOCATION_PROVIDER is signature|privileged, so a
/data/app microG can never hold it. The visible symptom is that framework
LocationManager apps get GPS only and every GNSS cold start is a blind
full-sky search, because the framework never calls injectLocation().

Every existing module in this category is unmaintained, and their hardcoded
privapp whitelists were written for GmsCore 0.3.4. On a device with
ro.control_privapp_permissions=enforce a missing whitelist entry does not
degrade, it bootloops. So derive the whitelist at install time by
intersecting microG's requested permissions with prot=*privileged*, and
abort rather than install a suspiciously short list.

Also relabels to u:object_r:system_file:s0. Files created under /data/adb
inherit adb_data_file, the bind mount preserves it, and system_server then
ignores them silently with no error in any log.

Tested on Pixel 9 Pro XL (komodo), LineageOS 23.2 / Android 16, microG
0.3.16, Magisk 30.7.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 23:52:44 +03:00
module feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00
.gitignore feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00
flake.lock feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00
flake.nix feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00
LICENSE feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00
README.md feat: systemize microG as a privileged app for the location provider slots 2026-08-01 23:52:44 +03:00

magisk-microg-priv

A Magisk module that makes an already-installed microG GmsCore a privileged system app, so Android will let it fill the framework's network and fused location provider slots.

It bundles no microG of its own. It systemizes whatever version you already have, and it generates its privileged-permission whitelist by reading the device it is being installed on.

The problem it solves

microG installed normally lives in /data/app. Android only binds the network location provider to a system or privileged app, and android.permission.INSTALL_LOCATION_PROVIDER is signature|privileged — a /data/app install can never hold it, no matter how it is configured.

The consequence is easy to miss. microG still serves apps that call the Play Services FusedLocationProviderClient directly, because that path needs no privilege. But it never feeds the framework LocationManager, so:

  • apps using the framework API (most F-Droid apps) get GPS only, and nothing indoors
  • the framework never calls injectLocation() on the GNSS engine, so every GNSS cold start is a blind full-sky search — minutes instead of seconds

Systemizing microG fixes both at once.

Why not one of the existing modules

Every module in this category is unmaintained. Checked 2026-08-01:

Module Last commit
microG Installer Revived 2024-12-06 (author: "reduced maintenance / no support mode")
MinMicroG 2024-07-21
microG_installer_Q 2021-01-04
terminal_systemizer 2019-10-23
App Systemizer 2017-09-18

That staleness is not cosmetic. Modules that bundle microG ship whitelists written for GmsCore 0.3.4, which omit privileged permissions that current microG requests. Generic systemizers write no whitelist at all. On a device with ro.control_privapp_permissions=enforce, a missing whitelist entry does not degrade — it bootloops the device.

So this module derives the list at install time instead of hardcoding it.

Requirements

  • Magisk (or another root solution that supports Magisk-format modules)

  • microG GmsCore already installed as a normal app

  • A ROM that permits an overlay network location provider. Check with:

    config_enableNetworkLocationOverlay      → true
    config_networkLocationProviderPackageName → @null (or com.google.android.gms)
    

    Read them out of framework-res.apk with aapt dump resources. If the overlay is disabled, or a different package is hardcoded, this module cannot work.

  • Install from the Magisk app, not recovery. The installer reads dumpsys from the running system to build the whitelist, and aborts if it cannot.

What it does

At install time, customize.sh:

  1. locates the installed microG APK via pm path, preferring the /data/app copy so it never sources the APK from its own mount
  2. copies it to /system/priv-app/GmsCore/GmsCore.apk
  3. builds the whitelist by intersecting microG's requested permissions: with prot=*privileged* from dumpsys package permissions
  4. aborts if it derives fewer than 5 permissions, rather than installing an incomplete whitelist that would bootloop the device
  5. relabels everything to u:object_r:system_file:s0

Your existing /data/app install becomes an UPDATED_SYSTEM_APP and keeps PRIVILEGED, so microG's settings and data survive.

Install

nix build              # produces result/magisk-microg-priv-2.0.zip

Then install the zip from the Magisk app, or:

adb push result/magisk-microg-priv-*.zip /data/local/tmp/
adb shell su -c 'magisk --install-module /data/local/tmp/magisk-microg-priv-*.zip'
adb reboot

Verify

adb shell dumpsys location | grep -A4 'network provider'

Success looks like:

network provider:
  enabled=true
  target service=…/org.microg.gms.location.provider.NetworkLocationProviderService
  connected=true
  last location=Location[network … hAcc=30.1]

Binding takes about three minutes after boot. Before that the provider reads target service=null, connected=false and the fused slot falls back to AOSP's com.android.location.fused. This is normal — do not conclude failure from an immediate check.

Gotchas worth knowing

SELinux. Files created under /data/adb get u:object_r:adb_data_file:s0. The bind mount preserves that context, and system_server then silently ignores them — no error, no log, the app just never becomes privileged. ls shows -?????????. The module handles this via set_perm_recursive, but if you build a module tree by hand, this is the trap.

cmd package query-services lies here. It reports "No services found" for the provider actions even as root, because it implies CATEGORY_DEFAULT and microG's intent filter declares no category. The actions are registered. Trust dumpsys location.

What this does not do

No signature spoofing. That is a separate mechanism, for apps that verify Play Services' identity, and it is not needed for location. If your ROM lacks it, location still works.

Tested on

Pixel 9 Pro XL (komodo), LineageOS 23.2 (Android 16), microG GmsCore 0.3.16, Magisk 30.7.

Licence

GPL-3.0-or-later.

module/META-INF/com/google/android/update-binary is Magisk's module_installer.sh, copyright topjohnwu, GPL-3.0. Everything else is original.