Summary
system_server dies with an unhandled IllegalStateException in
LocationEventLog$AggregateStats.markRequestBackground, causing a soft reboot
(framework restart — the kernel stays up). The stack trace is byte-identical
to the one in #26 apart from vendor line-number offsets, but on completely
different hardware and a different OEM framework, and it still occurs on
v0.1.3, the current release.
#26 was closed without a stated fix and its reporter was on v0.0.8/0.0.9. Filing
separately to establish that the bug is (a) not device- or OEM-specific and
(b) still present in the latest version.
Related: #49 (a separate, reproducible hook bug in the same subsystem on this
device).
Environment
|
|
| Device |
Redmi K90 Pro Max (25102RKBEC, codename myron) |
| Build |
Redmi/myron/myron:16/BP2A.250605.031.A3/OS3.0.306.0.WPMCNXM:user/release-keys |
| Android |
16 (SDK 36), HyperOS 3 |
| XposedFakeLocation |
v0.1.3 (versionCode 103) |
| Root |
KernelSU ksud 4.1.3 |
| Xposed |
LSPosed v2.1.1 (7790), ZygiskNext 1.4.3 |
| Module scope |
System Framework + several apps |
The crash
Happened once, ~14 hours into uptime, with the device lightly used but under
moderate load (load average 11.85). Not reproducible on demand.
FATAL EXCEPTION IN SYSTEM PROCESS: android.fg
java.lang.IllegalStateException
at com.android.internal.util.Preconditions.checkState(Preconditions.java:222)
at com.android.internal.util.Preconditions.checkState(Preconditions.java:207)
at com.android.server.location.eventlog.LocationEventLog$AggregateStats.markRequestBackground(LocationEventLog.java:728)
at com.android.server.location.eventlog.LocationEventLog.logProviderClientBackground(LocationEventLog.java:202)
at com.android.server.location.provider.LocationProviderManager$Registration.onForegroundChanged(LocationProviderManager.java:776)
at com.android.server.location.provider.LocationProviderManager.lambda$onAppForegroundChanged$14(LocationProviderManager.java:2749)
at com.android.server.location.provider.LocationProviderManager$$ExternalSyntheticLambda26.test(D8$$SyntheticClass:0)
at com.android.server.location.listeners.ListenerMultiplexer.updateRegistrations(ListenerMultiplexer.java:525)
at com.android.server.location.provider.LocationProviderManager.onAppForegroundChanged(LocationProviderManager.java:2749)
at com.android.server.location.provider.LocationProviderManager$$ExternalSyntheticLambda11.onAppForegroundChanged(D8$$SyntheticClass:0)
at com.android.server.location.injector.AppForegroundHelper.notifyAppForeground(AppForegroundHelper.java:71)
at com.android.server.location.injector.SystemAppForegroundHelper.lambda$onAppForegroundChanged$0(SystemAppForegroundHelper.java:59)
at com.android.server.location.injector.SystemAppForegroundHelper$$ExternalSyntheticLambda1.run(D8$$SyntheticClass:0)
at android.os.Handler.handleCallback(Handler.java:1029)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:274)
at android.os.Looper.loop(Looper.java:369)
at android.os.HandlerThread.run(HandlerThread.java:85)
at com.android.server.ServiceThread.run(ServiceThread.java:49)
Confirmed as a framework restart, not a kernel reboot: DropBox recorded
SYSTEM_RESTART (not SYSTEM_BOOT), sys.runtime.reboot.reason.last was
je#system_server#<ts>#unhandled, and /proc/uptime showed the kernel up
continuously for 13h51m across the event. No kernel panic, no pstore record, no
native tombstone.
Ruled out: thermal (status NONE, 36 °C battery, 54–60 °C CPU), battery/power
loss, storage, and native crashes.
Identical to #26 across two unrelated devices
| Frame |
#26 (Meizu 21 Pro) |
Here (Redmi K90 Pro Max) |
AggregateStats.markRequestBackground |
LocationEventLog.java:728 |
LocationEventLog.java:728 |
logProviderClientBackground |
LocationEventLog.java:202 |
LocationEventLog.java:202 |
Registration.onForegroundChanged |
LocationProviderManager.java:668 |
LocationProviderManager.java:776 |
ListenerMultiplexer.updateRegistrations |
:525 |
:525 |
AppForegroundHelper.notifyAppForeground |
AppForegroundHelper.java:71 |
AppForegroundHelper.java:71 |
SystemAppForegroundHelper.lambda$...$0 |
SystemAppForegroundHelper.java:59 |
SystemAppForegroundHelper.java:59 |
Only LocationProviderManager differs, as expected between vendor framework
builds. Two OEMs, two Android 16 images, same assert, same module.
The #26 reporter also noted the crash was not specific to Douyin and happened
with "all common app I used with location function." That matches here — no
single target app was in use at the moment of my crash.
Proposed mechanism
AggregateStats guards a foreground/background state machine with
Preconditions.checkState, so markRequestBackground throws if the counter is
already in the background state. Counters are keyed by
provider → uid/package[attributionTag] — visible in dumpsys location under
Historical Aggregate Location Provider Data — so a double-mark needs either two
registrations sharing one counter, or a registration whose foreground marker went
stale.
The module produces churn that can strand that marker. From dumpsys location,
it removes and re-adds its registrations within 1 ms, repeatedly:
15:44:57.649 network -registration 10388/com.noobexon.xposedfakelocation/0EE68DF0
15:44:57.649 gps -registration 10388/com.noobexon.xposedfakelocation/0EE68DF0
15:44:57.650 network +registration 10388/com.noobexon.xposedfakelocation/0EE68DF0 ← 1 ms later
15:44:57.652 gps +registration 10388/com.noobexon.xposedfakelocation/0EE68DF0
Over a 10-minute sample the module was the second-highest source of location
registration events on the device (14), behind only android itself. If an
app-foreground transition lands inside one of those remove/re-add windows, the
registration is torn down while still marked foreground and rebuilt fresh — so
the next background transition marks background on a counter that already
believes it is in the background. That is exactly the assert that fires.
What I have not proven
Being straightforward about the limits:
- No module frames appear in the fatal stack. It is entirely platform code.
- I could not reproduce on demand; it happened once in ~2 days of uptime.
- I could not capture the crash-time
dumpsys location, so I cannot name the
package whose counter desynced.
- An A/B test (module scoped to System Framework vs not) was inconclusive,
because the precursor state never occurred in either 10-minute window.
What makes this more than a guess is the cross-device stack match with #26 under
the same module, on unrelated hardware.
Hooks installed into system_server
25 methods on this build, for reference:
LocationProviderManager#onReportLocation
LocationManagerService#{getLastLocation, getCurrentLocation, requestGeofence,
addGnssMeasurementsListener, addGnssNavigationMessageListener,
addGnssAntennaInfoListener, registerGnssStatusCallback, registerGnssNmeaCallback}
GnssManagerService#{addGnssMeasurementsListener, addGnssNavigationMessageListener,
addGnssAntennaInfoListener, registerGnssStatusCallback, registerGnssNmeaCallback}
MiuiBlurLocationManagerImpl#{getBlurryLocation, getBlurryCellLocation,
getBlurryCellInfos, handleGpsLocationChangedLocked}
SystemServiceManager#loadClassFromLoader (see #49)
WifiServiceImpl#{getConnectionInfo, getScanResults}
PhoneInterfaceManager#{getAllCellInfo, getCellLocation, getNeighboringCellInfo,
requestCellInfoUpdateInternal}
Workaround
Un-scoping the module from System Framework in LSPosed (keeping it scoped to
individual target apps) removes all 25 hooks and eliminates the registration
churn from system_server; afterwards the module no longer appears anywhere in
dumpsys location. This disables system-wide spoofing, so it is a mitigation,
not a fix.
Suggested fixes
- Avoid the remove/re-add cycle when updating the module's own location
requests — update the existing registration in place, so no window exists in
which a foreground transition can strand the AggregateStats marker.
- Consider whether the module needs its own real
LocationManager registrations
inside system_server at all, given it already intercepts the delivery path
via LocationProviderManager#onReportLocation.
- If registrations must be recreated, doing so off the
android.fg handler, or
coalescing them, would narrow the race considerably.
I still have full logcat, LSPosed verbose/module logs, and dumpsys location
captures from before and after the crash, and am happy to run further diagnostics
or test a patch.
Summary
system_serverdies with an unhandledIllegalStateExceptioninLocationEventLog$AggregateStats.markRequestBackground, causing a soft reboot(framework restart — the kernel stays up). The stack trace is byte-identical
to the one in #26 apart from vendor line-number offsets, but on completely
different hardware and a different OEM framework, and it still occurs on
v0.1.3, the current release.
#26 was closed without a stated fix and its reporter was on v0.0.8/0.0.9. Filing
separately to establish that the bug is (a) not device- or OEM-specific and
(b) still present in the latest version.
Related: #49 (a separate, reproducible hook bug in the same subsystem on this
device).
Environment
25102RKBEC, codenamemyron)Redmi/myron/myron:16/BP2A.250605.031.A3/OS3.0.306.0.WPMCNXM:user/release-keysksud 4.1.3The crash
Happened once, ~14 hours into uptime, with the device lightly used but under
moderate load (load average 11.85). Not reproducible on demand.
Confirmed as a framework restart, not a kernel reboot: DropBox recorded
SYSTEM_RESTART(notSYSTEM_BOOT),sys.runtime.reboot.reason.lastwasje#system_server#<ts>#unhandled, and/proc/uptimeshowed the kernel upcontinuously for 13h51m across the event. No kernel panic, no pstore record, no
native tombstone.
Ruled out: thermal (status NONE, 36 °C battery, 54–60 °C CPU), battery/power
loss, storage, and native crashes.
Identical to #26 across two unrelated devices
AggregateStats.markRequestBackgroundLocationEventLog.java:728LocationEventLog.java:728logProviderClientBackgroundLocationEventLog.java:202LocationEventLog.java:202Registration.onForegroundChangedLocationProviderManager.java:668LocationProviderManager.java:776ListenerMultiplexer.updateRegistrations:525:525AppForegroundHelper.notifyAppForegroundAppForegroundHelper.java:71AppForegroundHelper.java:71SystemAppForegroundHelper.lambda$...$0SystemAppForegroundHelper.java:59SystemAppForegroundHelper.java:59Only
LocationProviderManagerdiffers, as expected between vendor frameworkbuilds. Two OEMs, two Android 16 images, same assert, same module.
The #26 reporter also noted the crash was not specific to Douyin and happened
with "all common app I used with location function." That matches here — no
single target app was in use at the moment of my crash.
Proposed mechanism
AggregateStatsguards a foreground/background state machine withPreconditions.checkState, somarkRequestBackgroundthrows if the counter isalready in the background state. Counters are keyed by
provider → uid/package[attributionTag]— visible indumpsys locationunderHistorical Aggregate Location Provider Data— so a double-mark needs either tworegistrations sharing one counter, or a registration whose foreground marker went
stale.
The module produces churn that can strand that marker. From
dumpsys location,it removes and re-adds its registrations within 1 ms, repeatedly:
Over a 10-minute sample the module was the second-highest source of location
registration events on the device (14), behind only
androiditself. If anapp-foreground transition lands inside one of those remove/re-add windows, the
registration is torn down while still marked foreground and rebuilt fresh — so
the next background transition marks background on a counter that already
believes it is in the background. That is exactly the assert that fires.
What I have not proven
Being straightforward about the limits:
dumpsys location, so I cannot name thepackage whose counter desynced.
because the precursor state never occurred in either 10-minute window.
What makes this more than a guess is the cross-device stack match with #26 under
the same module, on unrelated hardware.
Hooks installed into system_server
25 methods on this build, for reference:
Workaround
Un-scoping the module from System Framework in LSPosed (keeping it scoped to
individual target apps) removes all 25 hooks and eliminates the registration
churn from
system_server; afterwards the module no longer appears anywhere indumpsys location. This disables system-wide spoofing, so it is a mitigation,not a fix.
Suggested fixes
requests — update the existing registration in place, so no window exists in
which a foreground transition can strand the
AggregateStatsmarker.LocationManagerregistrationsinside
system_serverat all, given it already intercepts the delivery pathvia
LocationProviderManager#onReportLocation.android.fghandler, orcoalescing them, would narrow the race considerably.
I still have full logcat, LSPosed verbose/module logs, and
dumpsys locationcaptures from before and after the crash, and am happy to run further diagnostics
or test a patch.