GameCore 1.3
GameCore 1.3 — a cache cleaner that reports what it actually freed, a per-session
latency log that refuses to call anything packet loss, a session card you can share, and the four
bugs reported against 1.1.1.
Download
GameCore.apk — Android 8.0 (API 26) or newer, arm64-v8a and armeabi-v7a.
size 12,294,165 bytes (11.7 MB)
sha256 7c66e86ca7d4baac39e20916d8458af299fc544c24e9464b9c3642e091fb10b3
The release variant: R8 with obfuscation and resource shrinking, signed with the project's own
release key (CN=GameCore, RSA 2048) under the v2 APK signature scheme. Certificate SHA-256:
8eef17e0163198517f765b91a29aa9414710a852281b5e6fdd6362442586d42b
Same key as 1.0, 1.1 and 1.1.1, so this installs straight over any of them — versionCode 3 → 7.
With minSdk 26 the build omits the legacy v1 JAR signature, so the absence of META-INF/*.RSA
is expected and does not mean the APK is unsigned; apksigner verify reports it as verified under
v2.
Game storage
A screen under Settings that measures what every installed game is holding — cache, of which
clearable, and untouched — and clears one game's shared-storage cache on a tap.
The measurement is the feature. It reads the size, deletes, waits for the filesystem to settle,
reads again, and reports the difference between the two readings rather than the command's exit
code. A clear that freed nothing says nothing was freed, which is the opposite of what a booster app
does with the same situation. externalCacheBytes is API 31+, so on Android 11 and older the
clearable figure reads as needing a newer Android instead of a guessed fraction of the total.
The delete is one literal path — rm -rf /storage/emulated/<user>/Android/data/<package>/cache —
with the package name validated against the platform's own grammar, the user id derived from
GameCore's own uid, and the argv handed straight to exec. rm is the tenth program in the
closed elevated command set and it is reachable in exactly one form, asserted literally in the
command test so a second use cannot be added without that test failing. pm clear and
pm trim-caches stay forbidden. A game's private cache is out of reach at this privilege level and
the screen says so, offering Android's own storage page on every row rather than pretending
otherwise.
Measuring needs usage access; deleting needs Shizuku. Without either, the rows say which one is
missing.
What the connection did, across the whole session
A session now carries a latency log: probes that completed, probes that did not, the worst reply,
jitter, the longest unbroken run of failures, and a verdict — Stable, Spiky, Unreliable,
No reply or Not measured — with the figures behind the word in a sentence beside it.
A spike is twice the session's own running average and at least 40 ms above it, counted only
after three probes, so a fast link is not called spiky for one 12 ms wobble. "Stable" is withheld
until there is enough evidence for it, while one failed handshake is reported at once.
None of it is called packet loss. Android grants an app no raw sockets, so there is no ICMP ping
here; the probe is a timed TCP handshake, and a refused handshake is a probe that did not complete
rather than a dropped packet. There is no loss percentage anywhere in the app, and the wording is
deliberate at every read-out.
A card you can share
A finished session renders to a 1080×1260 PNG and goes out through your own share sheet, the way a
screenshot does.
Every string on the card is decided by a pure model that is unit-tested; the renderer only turns
those strings into pixels and holds no rule about an absent reading, so it cannot turn a dash into a
zero. A reading this device could not take is an em dash, and the caption says a dash is a reading
the device could not take rather than a zero. An interrupted recording prints its duration as a
lower bound. A per-hour battery figure appears only when the session was long enough to support one,
and falls back to the plain subtraction when it was not. The sample count travels with the averages,
and a handful of samples is not presented as an average at all.
The game's own label is the one string on the card GameCore did not write, so it is stripped of
control characters, collapsed, clamped, and kept out of the filename entirely. Cards are written to
the app's own files directory, at most four are kept, and the content:// URI never reaches a
composable — the ViewModel keeps it and hands the screen a boolean and an Intent. Nothing is
uploaded.
The four bugs
The crosshair drew the dot preset whatever you picked. Not a rendering fault. A request built
with crosshair = true and no preset id asks for a crosshair rather than the user's, and the
renderer cannot tell those apart, so it fell back to the lowest-numbered saved preset — which is the
dot. The id is now settled from the caller, the request already in hand, and the last preset picked,
in that order. The HUD had the identical bug and is fixed the same way, because a layout
somebody arranged is not "any layout".
A profile edited after leaving a game did nothing until GameCore was restarted. The profile is
re-read when a game starts and nowhere else, and a game returning after a real absence announced
nothing at all: the grace window that separates an interruption from a stop was applied to the game
going away but not to it coming back. A return after that window is now a stop dated when the game
left followed by a start dated now — stop first, so the previous sitting's values are restored
before the current profile is applied over them.
The resolution section stuck on "loading" after quitting a game. An unbounded pipe read while
holding the app-wide shell mutex: one command whose output never ended froze every later elevated
read behind it, and the display-size card is simply where a user notices first. The drain is bounded
now.
A Do Not Disturb popup put DND back on after you had turned it off by hand. Restore-on-exit had
no way to ask whether the value it was about to put back was still its own to put back. A write
ledger answers that: GameCore restores a device setting only when it made the write and nothing
outside GameCore has changed it since. Colour presets were the same bug in a second place, and are
fixed with the same ledger.
Under it
- Room schema 5, hand-written additive migration, schema JSON checked in — no destructive fallback.
- 293 JVM unit tests across 26 classes, no failures.
- The elevated command set is ten programs and still has no shell interpreter in it, so there is
still no string to inject into. Every argument is validated against a form before a command is
built, and a rejected argument produces no command at all rather than a malformed one. - No new network anywhere: the latency log reuses the existing TCP probe and its host setting, and
the card is drawn on the device.
Unchanged
The floating overlay, the performance pill, the HUD builder, the crosshair, per-game profiles,
monitoring, encrypted session tracking, colour correction, display size, the resizable panel — and
the absences: no root, no game-file modification, no code injection, no process memory access, no
anti-cheat interference, no fabricated statistics, no thermal-limit override, and nothing advertised
over a game.
Untested on hardware
The build host is an aarch64 device with no working adb, so the instrumented suite could not be
run and the overlay, Shizuku, colour-write, wm size, am kill and rm -rf paths have not
been exercised end to end on a phone by the build itself. The JVM suite covers the pure seams: the
samplers, the aggregators, the capability reasoning, the command builder, the cache selection, the
latency fold, and every string the shareable card is allowed to print.