Zero-Drain Power & Hardware Manager for Bigme HiBreak (MediaTek Helio P35 / MT6765)
Author: right9code
License: PolyForm Noncommercial 1.0.0 (Personal & Non-Commercial Use Only)
HiBig Zero is a dedicated, root-level power management and hardware tuning suite built specifically for the Bigme HiBreak B6 (Black & White and Color E-ink smartphones running Android 14).
Stock Bigme firmware suffers from severe active and standby battery drain caused by runaway vendor daemons, broken MediaTek power management policies, and unrestricted background services. HiBig Zero systematically neutralizes every measured drain source, dropping active reading drain by up to 500 mW and eliminating tens of thousands of background wakeups per day.
HiBig Zero ships with an E-ink native, strictly 1-bit monochrome interface:
- Responsive typography β every label uses Android sp text sizing and the system typeface, so text follows the device font scale instead of a hardcoded width-based scaler.
- Density-independent layout β all padding, margins, and dividers use dp, so the UI scales correctly across screen densities.
- Compact responsive banner β a two-line status strip showing the app name, version (
v1.5.0), and author (by right9code). - UPDATE button β one-tap GitHub release checker with in-app download, progress, and self-install.
- Clean tab bar β tabs are visually separated from the banner and from each other, use fixed labels, and mark the active tab with an underline indicator instead of a
>>prefix. - Collapsible sections β every section header (
HARDWARE,DEBLOAT,NETWORK,POWER,PACKAGE MANAGER, and the Battery sections) can be tapped to collapse or expand its body. - Package Manager clarity β the second tab is now
PACKAGE MANAGERwith aFREEZE, UNFREEZE, OR RESTRICTdescription. Each app row shows the name, package, and a plain-language status line (Not frozen | background: allowed | doze optimized | usage: ...) withFREEZE/UNFREEZEandOPTIONSstacked on the right. - Filter and sort dropdowns β the six cryptic filter chips (
RSTR,PROT) were replaced by a singleFILTER:selector with readable options, alongside the existingSORT:selector. - Dry run (plan-only mode) β a global switch that logs every state-changing action instead of applying it, so a whole rule set can be rehearsed safely. Status cards keep reading the real device state, and the banner shows
[ DRY RUN - NOTHING APPLIED ]whenever it is on. Per-feature dry runs (SHUTDOWN_TEST_MODE) still exist. - Charge ceiling β holds the battery at a configurable target (default
80%, resume75%) by switching the MediaTek charge input off and on, so a phone that lives on a charger is not held at 100% all night. It polls only while plugged in, and charging is restored the moment the cable comes out, whenever the feature is switched off, and at boot β a stuck "off" switch would mean a phone that never charges, so every failure path resumes rather than stops. - Removed non-essential controls β
PAGE UP/PAGE DOWNand the bulkFREEZE ALL/UNFREEZE ALL/RESTRICT USRshortcuts were removed; per-app actions remain in each row. - Strict 1-bit monochrome styling β all buttons, the search field, and the tab bar use explicit black/white bordered drawables, eliminating the system grey Material backgrounds.
- E-ink friendly glyphs β emoji and pictographs in menus and buttons were replaced with ASCII-safe labels for predictable rendering.
HiBig Zero includes a built-in App Installer that downloads, installs, and manages essential apps directly from GitHub releases β no Play Store or browser needed.
| App | Source | Install Type |
|---|---|---|
| AnyHome | right9code/AnyHome | Magisk system app |
| KOReader | koreader/koreader | User app |
| E-Ink Bro | plateaukao/einkbro | User app |
| Obsidian | obsidianmd/obsidian-releases | User app |
| MiXplorer | driftywinds/mixplorer-releases | User app |
| LocalSend | localsend/localsend | User app |
| Obtainium | ImranR98/Obtainium | User app |
- Resume & retry β downloads resume from where they left off if the connection drops, with 3 retries and exponential backoff.
- APK verification β file size is checked against the GitHub API before installing.
- SELinux-safe installs β APKs are staged to
/data/local/tmp/withchmod 644beforepm install -r -d -g. - MANAGE_EXTERNAL_STORAGE β automatically granted to KOReader, MiXplorer, and Obsidian on Android 14.
- Install permission β
REQUEST_INSTALL_PACKAGESis granted to Obtainium, so it can install APKs without a per-install confirmation prompt. - Magisk system app support β AnyHome is installed as a systemless Magisk module to
/system/priv-app/. - Version comparison β skips download if already on the latest version, handles
-rc1/-betasuffixes.
Tap the UPDATE button in the header to check for new releases of HiBig Zero itself:
- Fetches the latest release from
right9code/hibigzerovia GitHub API - Compares installed version with the latest tag
- Shows release notes and a one-tap UPDATE NOW or REINSTALL button
- Downloads with progress percentage, installs via root
pm install - Handles HTTP redirects, resume on failure, and APK verification
Updates and app installs are both fetched as root, so a misdirected download
is not a cosmetic problem. Two rules are enforced by NetGuard, shared by the
updater and the app installer so the policy cannot drift between them:
- HTTPS only, GitHub hosts only β
github.com,*.github.comand*.githubusercontent.com. Every redirect hop is followed manually and re-checked, withsetInstanceFollowRedirects(false)so the HTTP stack cannot make an unchecked hop of its own. A hop that leaves the list fails the download rather than falling back to the original URL. - Strict
host[:port]authority β any character that is not part of a hostname or port is refused, and ports other than 443 are rejected. This matters because URL parsers disagree:https://evil.com\@github.com/xis read as hostgithub.combyjava.net.URL(last@wins) while other clients treat\as/and connect toevil.com.
The updater additionally pins the signing key: a downloaded APK must be signed by the same certificate as the running app. Android enforces this at install time anyway, but checking first means a substituted download is reported as what it is instead of failing with an opaque installer error. The check fails closed.
| Optimization Area | Stock Firmware Behavior | HiBig Zero Optimized | Real-World Impact |
|---|---|---|---|
| PPM CPU Frequency Lock | Screen-ON locked Cluster 0 to 2.068 GHz max clock | Uncaps policy 7; drops idle clocks to 745β900 MHz | 300β500 mW active savings |
| CPU Core Hotplugging | All 8 cores active even when reading static pages | 4 Big cores dynamically offlined (cpu4-7) |
150β250 mW leakage reduction |
uart2serport Crash Loop |
Missing script spawns error loop every 2.5s (~34,500/day) | Injects clean stub; init crash-latch eliminated | CPU load drops from >25 to <2 |
| Gboard Telemetry & ML | 10+ background Superpacks/WorkManager jobs in Doze | Cancels jobs; restricts AppOps to foreground only | Zero deep-sleep interruptions |
| App Standby Buckets | All 200+ apps hardcoded to EXEMPTED (5) |
Granular bucket control (ACTIVE to RARE/RESTRICTED) |
Eliminates Doze bypasses |
| Inactivity Retention | Screen suspend blocker drained battery while idle | Auto-shutdown daemon powers off device to 0.00 mA | Unlimited static image retention |
- The Culprit: MediaTek's
mtkpowerHAL hard-locksPPM_POLICY_USER_LIMIT(Policy 7) whenever the display turns on, pinning Cluster 0 to 2.068 GHz and Cluster 1 to 1.515 GHz. - The Solution: Disables Policy 7 via
/proc/ppm/policy_statusand applies tunedschedutil_efficientgovernor scaling down to 900 MHz (Cluster 0) and 400β745 MHz (Cluster 1).
- Offlines cores 4β7 (
/sys/devices/system/cpu/cpu[4-7]/online = 0) on demand. - Provides a buttery-smooth reading experience in KOReader or Obsidian using 4 Little cores while entirely eliminating idle leakage across the Big cluster.
- Bigme's
PowerStandbyManagerinvokesctl.start uart2serporton every screen wake. Because/system/bin/start_uart2serport.shwas omitted from the EEA firmware, init crashed repeatedly. - Clears
sys.init.updatable_crashingand permanently quietsflags_health_check.
- Live queried package inspector with an E-ink friendly
OPTIONS βΎdropdown menu per app. - Freeze / Unfreeze: Disables bloatware via
pm disable-user --user 0. - AppOps Restrict: Blocks background wakelocks, background execution and foreground-service starts (
WAKE_LOCK,RUN_IN_BACKGROUND,RUN_ANY_IN_BACKGROUND,START_FOREGROUND), drops the app from the Doze whitelist and pins it to theRESTRICTEDstandby bucket. Network access is not touched: no appop exists for it. - Standby Bucket Selector: Seamlessly assigns apps to
ACTIVE (10),WORKING_SET (20),FREQUENT (30),RARE (40), orRESTRICTED (45). - Doze Exemption Toggle: Live control over Android Doze whitelist (
dumpsys deviceidle whitelist).
- Purges the Android 14
JobSchedulerqueue of all Google Superpacks dictionary and telemetry sync jobs. - Enforces
RUN_ANY_IN_BACKGROUND ignoreandSTART_FOREGROUND ignorewithout affecting normal foreground typing or offline autocorrect.
- A single
AlarmManageralarm (setExactAndAllowWhileIdle) is armed on screen-off and cancelled on screen-on. No shell daemon, no polling, no wakeups β the timeout costs 0 mA until it fires, then powers off withreboot -pto retain the current E-ink image. - Configurable timeout presets (
60m,120m,240m,480m) or a custom value. - Charging guard: a plugged-in device is rescheduled instead of powered off (nothing is saved by powering off a charger). Toggle
SKIP_WHILE_CHARGING. - Safety net: when the alarm fires the receiver re-checks
PowerManager.isInteractive()and a monotonic screen-off stamp, so a killed process or a stale alarm can never power the device off mid-use. Any error reschedules β it never fails open into a shutdown. - Single authority: enabling this also disables Bigmeβs own
PowersaveShutDownAlarmReceiver(re-asserted every boot), so two power-off timers can never compete.SHUTDOWN_TEST_MODElogs the decision instead of performing it.
- Real-time 3-second hardware polling:
- Battery Current: Discharge/charge current in mA.
- Battery Voltage & Temperature: Accurate readings from
mt6357-gauge. - CPU Frequencies: Cluster 0 & Cluster 1 clock speeds and governors.
- Online Core Detection: Real-time indicator for 8-Core vs 4-Core E-Reader mode.
- MediaTek PPM State: Live check of Policy 7 (
[UNCAPPED]vs[LOCKED]).
graph TD
App[HiBig Zero UI] --> Config[ConfigManager]
App --> Shell[ShellUtils ProcessBuilder]
App --> Installer[AppInstaller Engine]
App --> Updater[Self-Updater Engine]
Shell -->|Root su -c| Kernel[Linux Kernel 4.19 / MT6765]
Shell -->|Root su -c| AndroidOS[Android 14 Framework]
Installer -->|GitHub API| GitHub[GitHub Releases]
Updater -->|GitHub API| GitHub
Kernel --> PPM["/proc/ppm/policy_status (Policy 7 Uncap)"]
Kernel --> Hotplug["/sys/devices/system/cpu/cpu4-7/online (Hotplug)"]
Kernel --> PMIC["/sys/.../mt6357-gauge/ (Battery Current & Voltage)"]
AndroidOS --> AppOps["cmd appops (RUN_ANY_IN_BACKGROUND, WAKE_LOCK)"]
AndroidOS --> Jobs["cmd jobscheduler (Cancel Superpacks & WorkManager)"]
AndroidOS --> Standby["am set-standby-bucket (App Standby Buckets)"]
AndroidOS --> Doze["dumpsys deviceidle (Doze Whitelist)"]
Boot[System Boot] --> BootRec[BootReceiver]
BootRec --> Config
Every entry the UI shows is also appended to /data/local/tmp/hibreak.log
(mode 0600) by a single background writer thread. The writer batches, so a
burst such as an APPLY ALL RULES pass costs one root shell rather than one per
line. The payload is base64-encoded, so command output containing quotes,
backslashes or dollars cannot escape into the shell. The file rotates at 256 KB,
keeping the newest 128 KB.
Unlike the in-memory list it survives the process being reaped, which is the
point: the boot-time rule pass, charger events and the shutdown decision stay
readable afterwards. Receivers call ShellUtils.flushLog() before
PendingResult.finish(), because the process can be reaped the moment
finish() returns. The log popup shows the persisted tail merged with anything
not yet flushed.
Package names read back from /data/local/tmp end up inside su -c commands
that run on every boot, so a name is attacker-controlled input as far as the
shell is concerned. Two layers stop that:
- Ownership and mode. Files root writes but the app reads back (the config,
the frozen ledger, the restricted list, the active-governor marker) used to be
chmod 666, because root owns them and the app has to read them. They are now handed to the app's own uid with0600, falling back to0644if thechownis refused β which still cannot be tampered with by a non-root process. Those writes all flow through one helper,ConfigManager.secureFileTail(). - Validated names.
ConfigManager.isValidPackageName()admits no shell metacharacter, no whitespace and no leading-, and is applied where names enter a command (buildPmCmd,buildRestrictCmd,buildUnrestrictCmd,buildSetStandbyBucketCmd,buildDozeWhitelistCmd,splitPkgList) and where they are read back (loadRestrictedPkgs,loadFrozenLedger,recordFrozen). Standby buckets and governor profiles are allow-listed the same way. A rejected name yields an empty command, andexecRoot/execRootActionreturn without spawning a shell for it.
Worth knowing: /data/local/tmp is 0771 owned by shell, so this app cannot
unlink there even from a file it owns β the active-governor marker has to be
removed via root. File.delete() failed silently on that for a long time, which
left the marker behind permanently and made it useless as a "a clamp is applied"
flag.
The sleep clamp is applied by a dynamically registered receiver, and
ACTION_SCREEN_ON/OFF can only be received that way β they carry
FLAG_RECEIVER_REGISTERED_ONLY, so a manifest receiver cannot take the job over.
That makes the clamp depend on the process staying alive, and it does not.
This is not theoretical. Reproduced on device: clamp applied while asleep, kill -9
the process, press the power button β the screen comes on and cpu4 is still
offline with scaling_max_freq still 900000. A screen-on device stuck at
400β900 MHz with half its cores dead. Launching the app did not fix it either; only
toggling the screen again or rebooting would.
Two mechanisms now guarantee the repair:
- Reconcile on every process start.
HiBigApp.onCreateruns for any process start, including receiver-only ones, so the boot, power and alarm entry points are all covered by one call. If the screen is on and the marker says a clamp is applied, the user's profile is restored and the marker cleared. With no marker this is a single file stat and returns, so a normal launch costs no root shell. - A non-wakeup watchdog alarm, armed at screen-off and re-armed while the screen
stays off, in
SleepWatchdogReceiver. APendingIntentlives in the system's alarm queue, so it survives the process being killed and restarts it to be delivered. It usesELAPSED_REALTIME, not..._WAKEUP: a wakeup alarm would hold the SoC out of suspend to ask a question whose answer only matters once the device is awake. An elapsed-realtime alarm never wakes the device and is delivered when it next wakes β exactly when the answer changes. Verified: the framework registers it astype=ELAPSED, and an overdue one is delivered about two seconds after the power key.
Measured results (kill the process while clamped, then wake):
| Path | Outcome |
|---|---|
| Without the fix | stays clamped indefinitely |
| Cold start while the screen is on (any trigger) | repaired |
| Overdue watchdog delivered on wake | repaired 2 s after the power key |
| Normal screen offβon with the process alive | unchanged, immediate |
Residual window: at most one watchdog interval (90 s), and only when the process was killed and the screen comes back on before that interval expires and nothing starts the app. If the alarm has already expired it is delivered on wake, so a phone woken after a long sleep is repaired immediately rather than after 90 s.
The interval is a deliberate trade-off: a shorter one narrows the residual window but polls more often while asleep. The polling is cheap β non-wakeup, and Android rate-limits exact alarms during Doze, so it settles to the idle quota in deep sleep.
GovernorReconciler owns the marker file and the repair, so the semantics for "is a
clamp applied" and "how is it lifted" live in one place instead of being spread
across whichever receivers happen to touch it.
Note: the sleep clamp was measured on 2026-09-21 β see
docs/SLEEP_CLAMP_TEST.md. It saves ~10β17 mA while the device is awake with the screen off, and nothing at all while suspended (where the firmware powers the cores down regardless). The clamp's mechanism is verified, but the total-energy benefit cannot be measured on this device: the battery gauge is unusable below ~10 mA (charge_counterfrozen, positive current reported during discharge) and the timing/current instruments contradict each other by ~6Γ. Because the upside is small and bounded while the failure mode is a crippled device, the recommendation is to run withSLEEP_GOVERNOR_ENABLED=0.
A rule that loops the device is the worst failure this app can produce, and the
one failure the user cannot fix from inside the app β because the app is what is
looping. So the boot receiver counts boots: a boot within FAST_BOOT_SECONDS
(180 s) of the previous one is treated as a loop rather than a restart, and after
MAX_FAST_BOOTS (3) in a row the boot rule pass is suspended entirely,
including self-protection. "Suspended" has to mean the app touches nothing.
The count is written before any rule runs. If it were written afterwards, the one boot that matters most would be the one that never recorded it. The guard fails open: an unreadable state file restarts the streak at zero, because suspending rules on every fresh install would be far worse than missing one detection.
Suspension is surfaced in the header β [!!] RULES SUSPENDED: n fast boots in a row plus a RESUME RULES button β because a silently skipped rule pass just
looks like the app stopped working. RESUME and the normal APPLY ALL RULES
button do the same thing: clear the flag, reset the streak and apply. Neither
goes through the boot path, so a manual apply is never counted as a boot.
ShellUtils.execRoot() drains stdout and stderr on their own threads and gives
every command a deadline. Reading the two streams one after the other deadlocks
as soon as a command fills the pipe of the stream not yet being read, and an
unbounded waitFor() means a wedged su pins the calling thread forever β on
the UI thread, a permanent freeze. redirectErrorStream(true) would also fix the
deadlock but would erase the stdout/stderr split that CommandResult exposes, so
both streams are pumped separately instead.
Important
Root Access is Mandatory
HiBig Zero requires Superuser (Root) permissions via Magisk to communicate directly with MediaTek kernel sysfs nodes, uncap PPM frequency locks, dynamic hotplug CPU cores, and enforce boot rules.
If your Bigme HiBreak is not yet rooted, follow the comprehensive step-by-step guide included in this repository:
π Bigme B6 & HiBreak β Complete Rooting & Unbricking Guide
- Overcoming Single-Button Quirk: Uses
right9code/mtkclientwith hardware watchdog auto-reboot (--reboot) to bypass the physical button limitation. - Full Partition Backup: How to safely dump all 48 partitions before flashing.
- Magisk Patching: Extracting
boot_a.bin, patching via Magisk Manager, and flashing back safely. - One-Command Unbricking: Instant recovery to stock firmware if anything goes wrong.
- Device: Bigme HiBreak B6 (B&W or Color)
- OS: Android 14 (EEA / Global)
- Root: Magisk v26+ installed (see Rooting Guide)
- Download the latest APK from Releases:
HiBigZero-v1.5.0-release.apk
- Install via ADB:
adb install -r HiBigZero-v1.5.0-release.apk
- Open HiBig Zero on your device and grant Root (Superuser) permissions when prompted by Magisk.
- Tweak your desired toggles or switch to E-Reader Mode on Tab 1.
- Use the UPDATE button in the header to check for future updates.
The repository includes a zero-dependency build script that compiles Java 8 source directly into Dalvik bytecode using Android SDK build-tools:
- Java Development Kit (JDK 8 or JDK 17)
- Android SDK
platforms;android-35 - Android SDK
build-tools;35.0.0(aapt,d8,zipalign,apksigner)
python3 build.pyThe compiled, aligned, and signed APK is generated under releases/ together with its SHA-256 checksum file.
The build is signed with a key kept outside this repository (the repo is public, so a signing key must never be committed):
~/.config/hibigzero/hibigzero-release.jks # the key itself (chmod 600)
~/.config/hibigzero/keystore.properties # storeFile / storePassword / keyAlias / keyPassword
Override with HIBIGZERO_KEYSTORE, HIBIGZERO_KEYSTORE_PROPS, HIBIGZERO_STOREPASS if you keep them elsewhere.
All releases must be signed with the same certificate. Android refuses to update an app whose signature changed (INSTALL_FAILED_UPDATE_INCOMPATIBLE), so a new key orphans every existing installation - users can only recover by uninstalling and reinstalling.
build.py therefore:
- refuses to build if the keystore is missing (it will never silently mint a new identity),
- prints and verifies the certificate fingerprint on every build,
- prints a loud warning if the identity differs from the expected
c378f6f7....
To deliberately start a brand new identity: python3 build.py --init-key (then tell your users they must reinstall once).
History: builds up to v1.3.3 were signed with a key stored in
/tmp, which was lost when/tmpwas cleared (cert2238ad46...). v1.3.4 onward uses the persistent key above. Installations of v1.3.3 or older must be uninstalled once before they can be updated.
Copyright (c) 2026 right9code. All rights reserved.
This project is licensed under the PolyForm Noncommercial License 1.0.0 (LICENSE).
- Personal & Educational Use: Allowed and encouraged.
- Commercial Use: Strictly prohibited. You may not sell, monetize, incorporate into paid products, or distribute commercial forks of this software without explicit written permission from the author.
Developed with β€οΈ for the E-ink community by right9code.