Skip to content

Update for modern Android: fix carrier config override + build tooling - #35

Open
Dudeman456 wants to merge 2 commits into
nullbytepl:mainfrom
Dudeman456:update-modern-android
Open

Dudeman456 wants to merge 2 commits into
nullbytepl:mainfrom
Dudeman456:update-modern-android

Conversation

@Dudeman456

@Dudeman456 Dudeman456 commented Oct 2, 2026 •

Copy link
Copy Markdown

Problem

CarrierVanityName does not work on modern Android (14-17). Tested on Samsung Galaxy S26 Ultra (SM-S948U1), Android 17/API 37.

Root Causes (found via live ADB debugging)

1. Missing permissions → 0 SIM subscriptions

AndroidManifest.xml declared zero <uses-permission> entries. The app couldn't see any SIM subscriptions (found 0 subscriptions in logcat).

Fix: Added READ_PHONE_STATE, READ_BASIC_PHONE_STATE, READ_PHONE_NUMBERS + runtime permission request.

2. Direct ICarrierConfigLoader.overrideConfig() blocked

Calling overrideConfig() via ShizukuBinderWrapper on the carrier_config binder fails on Android 17:

SecurityException: overrideConfig cannot be invoked by shell

The shell UID (2000) is explicitly rejected at the binder level.

3. startDelegateShellPermissionIdentity from Activity context blocked

Calling CarrierConfigManager.overrideConfig() from a regular Activity with startDelegateShellPermissionIdentity fails:

SecurityException: Access denied, requires: android.permission.MODIFY_PHONE_STATE

Working Solution (mirrors eigenlux-ai/roamer)

Use an Instrumentation launched via Shizuku to run in a shell-identity context:

  1. Declare <instrumentation> as direct child of <manifest> (NOT inside <application> — otherwise "Unable to find instrumentation info")

  2. Launch via IActivityManager.startInstrumentation() through ShizukuBinderWrapper with INSTR_FLAG_NO_RESTART and a real UiAutomationConnection instance (passing null causes "Shell can delegate its permissions only to an instrumentation started from the shell")

  3. Inside the Instrumentation, call startDelegateShellPermissionIdentity via Shizuku, then CarrierConfigManager.overrideConfig() (the manager-level API, NOT the binder-level ICarrierConfigLoader). Use persistent=false — true is rejected on Samsung.

  4. After override, call notifyConfigChangedForSubId() to trigger the UI update.

New Files

  • PrivilegedOverrideInstrumentation.kt — Instrumentation that performs the override using shell permission delegation
  • InstrumentationTrigger.kt — Launches the Instrumentation via Shizuku's IActivityManager

Build Tooling (from previous commit)

  • AGP 7.4.1 → 8.7.3, Kotlin 1.8.0 → 2.1.0, Gradle 8.0 → 8.12
  • compileSdk/targetSdk 33 → 35, Java 8 → 11
  • Modern SIM enumeration via activeSubscriptionInfoList + createForSubscriptionId()
  • gradlew exec bit fix

Testing

Verified working on Samsung Galaxy S26 Ultra (SM-S948U1), Android 17/API 37, build CP2A.260605.016.S948U1UEU4BZID with Shizuku 13.5.4.

Jacob Suelyn added 2 commits October 2, 2026 19:49
The carrier config override was broken on Android 14+ due to:
1. Direct ICarrierConfigLoader.overrideConfig() call without shell permission delegation
2. Hidden SubscriptionManager.getSubId() / getNetworkOperatorName(subId) APIs
3. Outdated build tooling (AGP 7.4.1, Kotlin 1.8.0, compileSdk 33)

Changes based on the proven approach in eigenlux-ai/roamer:

TargetFragment.kt:
- Use CarrierConfigManager.overrideConfig() via reflection instead of direct ICarrierConfigLoader call
- Add withShellPermissionIdentity() via Shizuku-delegated ActivityManager for proper permission escalation
- Add SecurityException fallback (retry with override=false for OEM builds that reject true)
- Call notifyConfigChangedForSubId() after override to force system config reload
- Use public activeSubscriptionInfoList instead of hidden getSubId()
- Use public createForSubscriptionId() instead of hidden getNetworkOperatorName(subId)
- Improve reset: restore real ISO before clearing overrides
- Better error handling with user-visible toasts

MainActivity.kt:
- Add hidden API exemption for com.android.internal.telephony package

Build system:
- AGP 7.4.1 -> 8.7.3
- Kotlin 1.8.0 -> 2.1.0
- Gradle 7.5 -> 8.12
- compileSdk/targetSdk 33 -> 35
- Java 8 -> 11
- Update AndroidX deps (core-ktx 1.13.1, appcompat 1.7.0, material 1.12.0, navigation 2.8.4)
- Shizuku 13.1.0 -> 13.1.5
…hell permission delegation

Root cause analysis (tested on Samsung Galaxy S24 Ultra, Android 17/API 37):

1. Manifest had ZERO <uses-permission> declarations → app saw 0 SIM subscriptions.
   Added READ_PHONE_STATE, READ_BASIC_PHONE_STATE, READ_PHONE_NUMBERS + runtime request.

2. ICarrierConfigLoader.overrideConfig() via ShizukuBinderWrapper fails:
   'overrideConfig cannot be invoked by shell' (Android 17 rejects shell UID).

3. CarrierConfigManager.overrideConfig() + startDelegateShellPermissionIdentity
   from a regular Activity fails: 'requires MODIFY_PHONE_STATE'.

Working approach (mirrors eigenlux-ai/roamer):
- Declare <instrumentation> as direct child of <manifest> (NOT inside <application>).
- Launch PrivilegedOverrideInstrumentation via IActivityManager.startInstrumentation
  through ShizukuBinderWrapper with INSTR_FLAG_NO_RESTART + UiAutomationConnection.
  The UiAutomationConnection instance is REQUIRED — passing null causes
  'Shell can delegate its permissions only to an instrumentation started from the shell'.
- Inside the Instrumentation, call startDelegateShellPermissionIdentity via Shizuku,
  then CarrierConfigManager.overrideConfig() (manager-level API, not the binder-level
  ICarrierConfigLoader). persistent=true is rejected on Samsung; fall back to false.
- After override, notifyConfigChangedForSubId() triggers the UI update.

New files:
- PrivilegedOverrideInstrumentation.kt: Instrumentation running override logic
- InstrumentationTrigger.kt: launches the Instrumentation via Shizuku

Also: gradlew exec bit fix for Gradle builds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant