OP Band Control is an open-source KernelSU module for inspecting LTE/NR radio state and making guarded Android system-selection requests. It is designed for the OnePlus 15 reporting model CPH2747, with OxygenOS 16 as the primary experimental target.
Warning
Radio changes can interrupt mobile data, calls, SMS, IMS/VoLTE, roaming, handover, and emergency connectivity. Do not test while cellular service is your only way to reach emergency services. Keep Reapply after reboot off until a specific restriction has been tested thoroughly.
- Features
- What it does not do
- Compatibility
- Installation
- Using the WebUI
- Recovery and uninstall
- Troubleshooting
- Building locally
- Creating a GitHub release
- Contributing
- Privacy, security, and license
- Per-subscription SIM selector on Overview, Bands, and Profiles.
- Live serving-cell information from Android
PhysicalChannelConfig, including exposed primary and secondary LTE/NR carriers. - Registered and nearby bands observed through Android telephony cell information.
- Separate labels for CPH2747 advertised, observed nearby, and active now bands.
- Guarded, allowlisted LTE/NR
RadioAccessSpecifierrequests through Android's system-selection channel API. - Exact pre-change baseline capture and a 45-second rollback watchdog after numbered band-restriction writes.
- Idempotent LTE+ safeguard: applying it while the selected SIM is already automatic performs zero radio writes.
- Automatic rollback, manual undo, per-subscription baseline restoration, private operation logs, and opt-in boot reapply.
- Local WebUI assets, restrictive Content Security Policy, and no analytics or network dependency.
This module does not:
- Guarantee a hard serving-band, cell, EARFCN, or NR-ARFCN lock. Android documents the used API as a system-selection/background-scan restriction, and an OEM radio HAL may reject, ignore, or only partially implement it.
- Force LTE carrier aggregation, 4G+, or secondary-cell activation. The serving network and modem scheduler configure and activate LTE SCells.
- Force 5G NSA/SA, a preferred network mode, or 2G/3G band selection.
- Unlock RF bands missing from the physical antennas, filters, calibration, modem configuration, carrier provisioning, or certification.
- Amplify signal or guarantee higher speed, lower latency, or better coverage.
- Write Qualcomm QMI/DIAG/NV/EFS data, IMEI, RF calibration, carrier policy, IMS settings, or
persist.radio.*properties. - Restart the modem, toggle airplane mode, or make SELinux permissive.
Root access grants permission to call available Android services; it cannot create a missing vendor API or override a modem/network rejection.
- Android 12 / API 31 or newer
- 64-bit ARM (
arm64/arm64-v8a) - KernelSU Manager with Module WebUI support
- A firmware radio implementation that exposes the required Android telephony APIs
Android 12 is the technical installation floor, not a claim that every Android 12+ ROM is supported.
| Device / platform | Installation | Monitoring | Band requests | Support level |
|---|---|---|---|---|
OnePlus 15 CPH2747, OxygenOS 16 / Android 16, arm64, KernelSU |
Yes | Best effort | Experimental and verified per request | Primary experimental target |
Chinese/converted hardware reporting CPH2747 with global firmware |
Yes | Best effort | Unverified | Experimental; monitor first and keep boot reapply off |
| Other OnePlus device, Android 12+, arm64, KernelSU | Installer warns but allows | May work | Unsupported: the bundled numbered-band catalog is CPH2747-specific | Monitoring-only best effort |
| Other OEM, Android 12+, arm64, KernelSU | Installer warns but allows | May work | Unsupported | Monitoring-only best effort |
| Android 11 / API 30 or older | Installer aborts | No | No | Unsupported |
| 32-bit ARM, x86, or x86_64 Android | Installer aborts | No | No | Unsupported |
| Magisk, APatch, custom recovery, or a normal browser | Unsupported installation/UI path | Browser shows preview/mock data only | Not supported | Use KernelSU Manager |
The current build uses the official CPH2747 LTE/NR catalog for all mutation validation. The installer warns on a different manufacturer or model but does not hard-block it, so do not apply numbered profiles on other devices.
A property such as ro.product.model=CPH2747 identifies the running firmware, not the original RF hardware. Global firmware cannot add missing antennas, filters, calibration, modem capabilities, carrier provisioning, or certification. Treat a converted Chinese device as unverified hardware even when the WebUI reports CPH2747.
An OxygenOS or Android OTA can change hidden/System APIs and vendor RIL behavior. Disable boot reapply before an OTA, reboot after updating, and re-test monitoring and recovery before applying another restriction.
-
Open this repository's Releases page.
-
Download
op-band-control-vX.Y.Z.zip. Do not extract or rename it. -
Optionally download the matching
.zip.sha256file and verify it on a computer:sha256sum --check op-band-control-vX.Y.Z.zip.sha256
-
Open KernelSU Manager → Modules → Install from storage.
-
Select the ZIP and review the installer warnings.
-
Reboot the phone.
-
Open OP Band Control from the module's WebUI button.
-
Inspect Overview for each SIM before applying anything. Fresh installs start with boot reapply off.
Do not flash this ZIP from custom recovery. Magisk and APatch are not supported by this build.
- Disable Reapply after reboot.
- If this module currently owns a numbered restriction, restore that SIM to automatic selection first.
- Install the newer ZIP over the existing module in KernelSU Manager.
- Reboot and verify both SIMs again before making another request.
Configuration under /data/adb/opband-control may survive an update, so an earlier opt-in boot setting should not be assumed to reset automatically.
- CPH2747 advertised: static list from OnePlus documentation; not proof of a converted device's physical RF chain.
- Observed nearby: cached or partial Android cell data; not a complete modem capability list.
- Active now: serving channels reported by Android. Secondary carriers can disappear while traffic is idle.
Android does not provide a standard API that enumerates every numbered LTE/NR band configured in a modem.
| Profile | Behavior | Important limitation |
|---|---|---|
| Adaptive | Clears the current Android system-selection restriction for the selected subscription | May also clear an OEM or third-party restriction; use deliberately |
| Coverage | Restricts scanning to observed lower-frequency candidates | Deployment is carrier/country specific and service can be lost |
| LTE+ safeguard | Leaves an automatic SIM untouched; clears a restriction only when this module proves ownership on that same subscription | Does not force 4G+; it prevents this module from excluding a valid CA combination |
| 5G NSA candidate | Keeps observed LTE anchors and NR candidates eligible | Requires carrier-side NSA and a compatible LTE anchor |
| Custom | Uses the exact LTE/NR choices selected on Bands | Expert use; easy to interrupt service |
B32 and n75 are supplemental-downlink bands. The UI and backend reject them as the only selected bands. The NSA profile also requires an ordinary LTE anchor.
- Choose the target SIM on Profiles or Bands. The displayed subscription ID is not necessarily the physical slot number.
- Choose a profile or manual LTE/NR bands.
- Select Review & apply and verify the subscription and requested bands.
- Hold Hold to apply. Keyboard and switch users press Enter twice.
- Test mobile data, calls, SMS, IMS/VoLTE, roaming, and handover.
- Select Keep this change before the 45-second timer expires, or select Undo now.
Closing KernelSU does not cancel the watchdog. If confirmation never arrives, the controller restores the exact pre-change selection.
- Applying LTE+ safeguard to an already-automatic SIM is an immediate no-op and should report
"changed":false,"noOp":true; no watchdog is necessary because no radio write occurred. - Adaptive and Restore defaults clear a non-empty system-selection restriction immediately.
- Restore defaults is intentionally broader than LTE+ safeguard. It can clear a restriction created by an OEM or another tool, so use it only when that is intended.
Boot reapply is off by default on a fresh installation. It is available only after a numbered restriction has been confirmed. A failed boot reapply disables itself instead of retrying indefinitely.
Only one current confirmed/reapply configuration is tracked at a time, although uninstall baselines are captured separately per subscription. A vendor may also implement a nominally per-subscription policy modem-wide; test one SIM at a time.
Use the first recovery method that remains available:
-
WebUI → choose the affected SIM → Restore defaults.
-
KernelSU's module action button. It targets the preferred active subscription, normally the active/default-data SIM.
-
From a root shell, replacing the example ID
5with the numeric subscription ID reported bystatus:su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh reset 5' -
If a change is pending, wait for the 45-second watchdog or use Undo now.
Before uninstalling, restore every active SIM on which this module applied a restriction when possible. Then remove the module in KernelSU Manager and reboot. uninstall.sh attempts to restore every captured per-subscription baseline. If a SIM is unavailable or a restore fails, the private fallback state is intentionally retained under /data/adb/opband-control for later recovery.
| Symptom | Meaning / action |
|---|---|
| Read-only on this firmware or disabled apply buttons | The backend could not verify the subscription, READY SIM/slot mapping, exact selection read, or setter API. Root alone cannot make this writable. |
| MODEM_REJECTED or CALLBACK_TIMEOUT | The firmware/modem rejected the request or did not acknowledge it. Restore defaults if needed; do not retry continuously. |
| Only one SIM appears, or service is shown incorrectly | Confirm both SIMs are enabled and unlocked, then collect status diagnostics after telephony has finished starting. |
| Another radio change is in progress | Wait for the bounded operation and retry. Do not manually delete lock files while a controller process may be live. |
| PENDING_CHANGE | Keep or undo the pending change in the WebUI, or wait for automatic rollback. |
| LTE+ changed from 4G+ to plain 4G on an older build | Upgrade to v0.1.5 or newer. With automatic selection, LTE+ safeguard now makes zero radio writes. |
# All detected subscriptions and the preferred subscription
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh status'
# Example ID 5 must be replaced with a numeric subId from status;
# a subscription ID is not the SIM slot number
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh status 5'
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh selection 5'
# Saved profile, owner subscription, boot reapply, and pending state
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh settings'
# Recent privacy-filtered controller events
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh logs 200'
# Disable boot reapply without changing the current radio selection
su -c 'sh /data/adb/modules/opbandcontrol/bin/control.sh set-reapply off'Before posting diagnostics publicly, inspect and redact carrier/display names, subscription IDs, PCI/channel/frequency details, build fingerprints, and pending/restore tokens as appropriate. The module does not intentionally query IMSI, IMEI, or phone numbers.
For a useful bug report, include:
- Manufacturer, exact device model, and whether the hardware was region-converted
- Android version, ROM name/version, and KernelSU Manager version
- Whether the SIM is physical/eSIM and single-SIM/dual-SIM
- The exact action performed and whether service recovered automatically
- Redacted
status,selection <subId>,settings, andlogs 200output
- JDK 17 or newer, providing
javacandjar - Android SDK Platform 35
- Android SDK Build Tools 35.0.0 with
d8 - Node.js 20 or newer
- POSIX shell tools,
zip, andunzip
Set ANDROID_SDK_ROOT or ANDROID_HOME to the Android SDK. The project has no npm runtime dependencies, so no npm install step is required.
npm run check
npm run buildnpm run check validates shell scripts, controller behavior, JavaScript syntax, backend/UI regression tests, CSP, and safety invariants. npm run build rebuilds bin/opband.jar, reruns validation, and creates:
dist/op-band-control-v<module.prop version>.zip
The ZIP has KernelSU module files at its root; do not wrap them in another directory.
| Path | Purpose |
|---|---|
helper-src/ |
Privileged Java telephony helper compiled to bin/opband.jar |
bin/control.sh |
Allowlisted root controller, state, lock, watchdog, and rollback logic |
webroot/ |
Local KernelSU Module WebUI |
tests/ |
Controller fixtures and backend/UI regression tests |
scripts/ |
Helper build, validation, and ZIP packaging |
.github/workflows/release.yml |
CI build and tagged GitHub Release automation |
The included GitHub Actions workflow validates pull requests and pushes, produces a downloadable Actions artifact, and publishes a GitHub Release only for a matching version tag.
-
Update
versionand increaseversionCodeinmodule.prop. -
Set the same semantic version in
package.json. -
Update the
?v=cache-busting values forapp.cssandapp.jsinwebroot/index.html. -
Update release notes/documentation and run:
npm run check npm run build unzip -t dist/op-band-control-vX.Y.Z.zip
-
Commit the release changes using your normal reviewed workflow.
-
Create and push an exact matching tag:
git tag vX.Y.Z git push origin vX.Y.Z
For example, module.prop version 0.2.0 requires tag v0.2.0. A mismatched or malformed tag fails before publishing.
On a valid tag, the workflow:
- Uses JDK 17, Node.js 22, Android Platform 35, and Build Tools 35.0.0.
- Verifies
module.prop,package.json,versionCode, and the tag. - Runs all validation/tests and builds the installable ZIP.
- Checks ZIP integrity and the embedded module version.
- Generates and verifies a SHA-256 checksum.
- Uploads the ZIP and checksum as a short-lived Actions artifact.
- Creates a GitHub Release with generated notes and attaches both files.
A manual workflow_dispatch run builds and uploads an Actions artifact, but does not publish a GitHub Release. The workflow defaults to read-only repository permission; only the tag release job receives contents: write.
Issues and pull requests are welcome. Keep changes narrowly scoped and explain any radio behavior assumptions.
Before opening a pull request:
- Run
npm run checkandnpm run build. - Preserve strict argument allowlists between the WebUI and root controller.
- Keep writes reversible, subscription-specific, and guarded by exact pre-change capture.
- Add regression tests for parser, dual-SIM, rollback, and UI state changes.
- Clearly label behavior that has not been verified on physical hardware.
Proposals that guess Binder transaction numbers, write QMI/DIAG/NV/EFS or identifiers, disable thermal protection, make SELinux permissive, or promise forced carrier aggregation will not be accepted.
- No analytics, telemetry upload, remote JavaScript, CDN, or external frame is used by the module.
- Controller logs are stored privately and intentionally omit subscriber identities and precise cell identifiers.
- WebUI commands use argument arrays; the root controller independently validates verbs, profiles, subscription IDs, bands, and tokens.
- KernelSU configuration is used when available, with a private persistent fallback at
/data/adb/opband-control.
For a security vulnerability, prefer GitHub's private Security → Report a vulnerability flow when enabled. Do not publish sensitive exploit details, subscriber data, or live recovery tokens in a public issue.
This project is licensed under the Apache License 2.0. See THIRD_PARTY_NOTICES.md for bundled third-party attribution.
- KernelSU module guide
- KernelSU Module WebUI
- OnePlus 15 CPH2747 quick guide
- Android
PhysicalChannelConfig - Android 16
TelephonyManager - AOSP Radio HAL
IRadioNetwork - 3GPP carrier aggregation overview
The repository includes static validation, helper compilation, controller fixtures, unit/regression tests, browser interaction checks, responsive WebUI checks, and ZIP-layout verification. These tests do not replace real-device modem testing. Repository-based validation has not established universal support for CPH2747/OxygenOS 16 or any other firmware, so all radio writes remain experimental and fail closed where capability cannot be verified.