Skip to content

Add Shizuku-powered rootless USB tethering and WiFi Hotspot - #5903

Open
eliotcougar wants to merge 45 commits into
2dust:masterfrom
eliotcougar:shizuku-tethering
Open

Add Shizuku-powered rootless USB tethering and WiFi Hotspot#5903
eliotcougar wants to merge 45 commits into
2dust:masterfrom
eliotcougar:shizuku-tethering

Conversation

@eliotcougar

@eliotcougar eliotcougar commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a rootless tethering implementation that routes devices connected through the Android Wi-Fi hotspot or USB tethering through the active v2rayNG connection. Fixes #5898

Privileged Android networking operations are performed through a user-approved Shizuku UserService running as the shell UID. No root access, iptables manipulation, or custom DHCP/NAT implementation is required.

The feature supports both existing v2rayNG TUN implementations:

  • hev-socks5-tunnel
  • Native Xray-core TUN

It also follows profile changes and service restarts. When the main v2rayNG connection changes, the tethering datapath is synchronized with the new running configuration and active Wi-Fi/USB tethering modes are preserved where Android permits this.

Motivation

Android’s regular VpnService protects traffic originating from the Android device itself. Traffic forwarded by Android’s tethering stack does not normally enter that VPN, so clients connected through a hotspot or USB tethering can bypass v2rayNG entirely.

Root-based solutions can redirect forwarded traffic with firewall and policy-routing rules, but this is not available on locked, non-rooted devices.

This implementation uses Android’s test-network infrastructure through Shizuku to provide the tethering stack with a protected upstream network without requiring root.

User-facing changes

Realigned Shizuku Tethering screen

A new Tethering page is available in the navigation drawer below Backup & Restore.

The page provides:

  • Current Shizuku availability and permission status
  • Buttons to request or refresh Shizuku permission
  • Current v2rayNG tethering state
  • The active routing engine and profile
  • Wi-Fi hotspot status
  • Wi-Fi hotspot enable/disable control
  • USB tethering detection
  • Errors returned by the privileged tethering service

Starting the Wi-Fi hotspot from this page automatically establishes the protected v2rayNG tethering route first.

USB tethering may be enabled from Android settings. If v2rayNG tethering routing is active, Android’s USB tethering traffic uses the same protected upstream.

All new user-facing strings are localized for every locale currently present in the project.

Working principle

1. Shizuku provides the privileged execution context

After the user grants permission, v2rayNG starts a daemon-style Shizuku UserService. The service executes under Android’s shell UID and owns the privileged tethering datapath.

The regular app process does not receive permanent system networking permissions. Shizuku remains the authorization boundary, and the user can revoke access through Shizuku at any time.

2. The exact running configuration is captured

The normal v2rayNG core records a snapshot of the configuration that was actually used to start the current connection.

This is intentionally different from rebuilding a configuration from preferences: settings or the selected profile may have changed after the running core was started.

The snapshot includes:

  • Active profile name
  • Whether HEV or native Xray TUN is being used
  • Generated Xray configuration
  • Local SOCKS endpoint and optional authentication
  • VPN MTU
  • HEV timeout and logging parameters
  • Required Xray asset and XUDP initialization information

The feature requires v2rayNG to be running in VPN mode before protected tethering can be enabled.

3. Android creates the tethering TUN

Through the shell context, the UserService accesses Android’s hidden TestNetworkManager service and:

  1. Creates a kernel TUN interface using createTunInterface.
  2. Assigns the interface the internal IPv4 address 192.0.2.2/24.
  3. Publishes it as an Android test network using setupTestNetwork.
  4. Waits for ConnectivityManager to report that network.
  5. Calls the hidden TetheringManager.setPreferTestNetworks(true) API.

Android’s existing tethering stack then selects the test network as its upstream. Android continues to provide the downstream Wi-Fi/USB interface, DHCP, forwarding, NAT, and tethering lifecycle management; v2rayNG only consumes the upstream TUN traffic.

4. The selected TUN engine consumes the traffic

HEV mode

A second HEV instance runs inside the dedicated Shizuku process. Native HEV state is process-global, so using a separate process allows this instance to coexist with the HEV instance serving the normal Android VPN.

The tethering HEV instance consumes the test-network TUN and sends its traffic to the SOCKS inbound of the normal running v2rayNG core.

This means the tethered traffic ultimately uses the active core’s outbounds, DNS behavior, balancing, and applicable routing rules.

Native Xray TUN mode

A second Xray controller is created inside the Shizuku process.

Its configuration is derived from the exact running Xray configuration. Non-TUN inbounds are removed to avoid conflicting with ports already owned by the main core. The following sections remain available to the tethering core:

  • TUN inbound
  • Outbounds
  • DNS
  • Routing rules
  • Balancers
  • Observatory configuration
  • Other supporting runtime configuration

The second controller consumes the test TUN file descriptor directly.

5. Android tethering is started or attached

The UserService monitors active tethering types through TetheringManager.TetheringEventCallback.

The page can start or stop Wi-Fi tethering directly. USB tethering started from Android settings is detected and uses the protected test-network upstream while routing is active.

6. Profile changes and service restarts are synchronized

The main core sends authenticated lifecycle events to the Shizuku service:

  • Core stopping
  • Core started with a new configuration
  • Core start failed

Events are ordered through a single dispatcher and protected by a random per-session token.

When the user changes profiles or restarts v2rayNG, the service:

  1. Records which tethering types are active.
  2. Keeps the protected test TUN alive where possible.
  3. Stops the old HEV/Xray tethering engine.
  4. Starts the new engine with the new running configuration.
  5. Restores any Wi-Fi or USB tethering types that had to be temporarily stopped.

The preferred path switches the routing engine in place while retaining the existing TUN. If that fails, the implementation falls back to rebuilding the test network. The fallback stops tethering before removing the protected route and restores it afterward.

A short traffic interruption is still possible during a profile or implementation change. Android or an OEM tethering stack may also force hotspot clients to reconnect.

7. Fail-closed cleanup

The implementation deliberately avoids silently falling back to an unprotected upstream.

In particular:

  • Disabling v2rayNG tethering stops active tethering before removing the protected route.
  • A failed configuration synchronization attempts to stop active tethering before cleaning up the test network.
  • If Android refuses to stop tethering, the protected test network is retained rather than knowingly exposing clients through a direct connection.
  • Cleanup restores setPreferTestNetworks(false), unregisters callbacks, tears down the test network, closes the TUN, stops the secondary engine, and removes temporary HEV configuration.

Routing semantics

Most normal network-based routing behavior remains available, including rules based on:

  • Domain
  • Destination IP
  • Port
  • Protocol
  • Inbound metadata available to the tethering core
  • Balancer and observatory results

However, per-app and process-based routing cannot apply to tethered devices.

Android and Shizuku requirements

The current implementation should be treated as requiring Android 16 / API level 36 or newer.

Although the application itself retains its existing minSdk of 24, this feature uses API-level-36 tethering types and signatures if they are available, including:

  • TetheringManager.StopTetheringCallback
  • stopTethering(TetheringRequest, Executor, StopTetheringCallback)
  • TetheringEventCallback.onTetheredInterfacesChanged(Set<TetheringInterface>)
  • TetheringInterface

The fallback method has been added to cover Android 11-15.

See the Android TetheringManager reference and TetheringEventCallback reference.

Additional requirements are:

  • Shizuku v11 or newer
  • Shizuku running and permission granted to v2rayNG
  • v2rayNG running in VPN mode
  • Android’s test_network system service
  • Compatible hidden TestNetworkManager methods
  • Compatible hidden TetheringManager.setPreferTestNetworks(boolean)
  • Shell UID access to MANAGE_TEST_NETWORKS and NETWORK_SETTINGS
  • Wi-Fi hotspot or USB tethering supported and permitted by the device
  • Carrier entitlement and device-policy checks allowing tethering

TestNetworkManager and setPreferTestNetworks are System/hidden APIs rather than stable third-party application APIs. Their AOSP permission and API definitions can be seen in AOSP TestNetworkManager and AOSP TetheringManager.

Device compatibility warning

Passing the Android version check does not guarantee compatibility.

This implementation depends on behavior below the ordinary Android application API surface. OEMs may:

  • Remove or rename hidden methods
  • Change method signatures
  • Restrict shell UID networking permissions
  • Modify test-network selection
  • Replace or customize the Connectivity/Tethering module
  • Apply additional hotspot entitlement checks
  • Restrict Shizuku or wireless debugging in the background
  • Disable tethering through device policy or system configuration

AOSP itself permits tethering to be disabled by system properties, device configuration, device policy, and carrier entitlement. Carrier configuration may also reject cellular tethering even if Wi-Fi hotspot hardware is present. See the AOSP tethering implementation and entitlement manager.

Known Shizuku setup friction exists on MIUI/HyperOS, ColorOS, Flyme, EMUI, Sony firmware, and some hardened Android distributions. These are not necessarily missing networking features, but they may require additional developer-option changes or background-execution allowances. See the Shizuku setup guide.

Initial testing has covered a Pixel 9 Pro running Android 16 and a Google/AOSP emulator running Android 15 and 17. This should not be interpreted as a complete OEM compatibility matrix.

Potential conflicts

Users should avoid running this feature simultaneously with:

  • v2rayNG’s root-based LAN/tethering forwarding
  • Other root tethering or VPN-hotspot applications
  • Tools that create Android test networks
  • Tools that change tethering’s preferred test-network state
  • Other software that programmatically starts or stops the same tethering type
  • Device-management software that enforces hotspot restrictions

Android normally allows only one active VpnService, so replacing v2rayNG with another VPN also invalidates the protected tethering route.

The feature uses Android’s existing persistent hotspot configuration. It does not manage the hotspot SSID, password, band, channel, or client allowlist.

Security and trust considerations

The native Xray mode passes the exact running Xray configuration to the Shizuku UserService. This configuration may contain server credentials or other sensitive connection parameters.

The privileged UserService is therefore inside the Shizuku trust boundary. Users must trust both Shizuku and the installed v2rayNG build before granting permission.

To limit internal spoofing and stale updates:

  • The synchronization receiver is not exported.
  • Broadcasts are explicitly restricted to the v2rayNG package.
  • Lifecycle synchronization uses a random session token.
  • Updates with an inactive or invalid token are rejected.
  • The privileged AIDL service is not exposed as a normal exported Android service.
  • Temporary HEV configuration is removed during cleanup.

Implementation overview

This PR introduces:

  • Shizuku API and provider dependencies
  • AIDL support
  • A shell-owned tethering UserService
  • Test-network TUN lifecycle management
  • Wi-Fi and USB tethering state tracking
  • HEV and native Xray tethering engines
  • Core configuration snapshots
  • Profile and service lifecycle synchronization
  • Fail-closed tethering cleanup
  • Tethering status and controls UI
  • Complete localization for all existing app locales

Validation

  • :app:assembleDebug succeeds for both F-Droid and Play Store variants.
  • All localized resource sets compile successfully.
  • HEV and native Xray TUN paths have been exercised.
  • Wi-Fi hotspot control and protected routing have been exercised.
  • Profile switching and service restart synchronization have been exercised.
  • Active tethering restoration has been exercised.
  • Manual testing has been performed on Android 16 hardware and an Android 17 emulator.

Known limitations and future work

  • Android 15 and earlier are not supported by the current implementation.
  • Compatibility depends on hidden APIs and OEM networking behavior.
  • Per-app and process-based routing cannot apply to tethered clients.
  • The protected test-network upstream is currently IPv4-only.
  • Profile switching may cause a brief traffic interruption.
  • A broader OEM and carrier test matrix is still required.
  • Runtime capability probing can be expanded to report specific missing APIs or permissions before starting the route.
  • Compatibility fallbacks would be required to target earlier Android releases.

@eliotcougar

Copy link
Copy Markdown
Contributor Author

@2dust Do you want me to try trimming down and simplifying this PR more over the weekend? Rootless tethering is a really cool and useful feature to have. I've tested it, it works well on my Pixel 9.

@eliotcougar
eliotcougar force-pushed the shizuku-tethering branch 2 times, most recently from 9c1f7a0 to 9d3c593 Compare July 20, 2026 20:11
@eliotcougar

Copy link
Copy Markdown
Contributor Author

I've spent way too much time chasing this random issue where enabling tethering can occasionally choose a physical interface instead of testtun, and pass traffic from tethered device around v2rayNG straight to clearnet...

Random bugs are the worst... 🫩

A software tester walks into a bar. Runs into a bar, Crawls into a bar, Dances into a bar, Flies into a bar, Jumps into a bar.
And orders: A beer, 2 beers, 0 beers, 9999999999 beers, A lizard in a glass, -1 beer, "qwertyuiop" beers...
Testing complete.

A real customer walks into the bar and ask where the toilets are.
The bar goes up in flames.

@2dust

2dust commented Jul 21, 2026

Copy link
Copy Markdown
Owner

感谢你的 PR
但是个人认为此功能用起来太繁琐了,且代码量巨大,后期维护很麻烦。

  1. 首选 Android 16 (API Level 36) 及以上
  2. 需安装并运行 Shizuku
  3. 仅支持 IPv4
  4. 可能在很多设备上被限制

请问是否总结的到位?

@eliotcougar

eliotcougar commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

感谢你的 PR 但是个人认为此功能用起来太繁琐了,且代码量巨大,后期维护很麻烦。

  1. 首选 Android 16 (API Level 36) 及以上

It no longer requires API36+, it now works all the way to Android 11. 13. The initial dependence on API36 was superficial.
Tethering API is convenient in Android 16+, but not strictly necessary to control tethering.

Correction: Apparently, setPreferTestNetworks doesn't exist in Pixel 5 API 30 framework... AI lied to me... The earliest is API33 Android 13... Just confirmed it running on Pixel 6a API33 image...
We're currently looking for a workaround for API30-32… GPT5.6 is trying one PoC after another on the running emulator right now…

  1. 需安装并运行 Shizuku

Installing Shizuku isn't difficult, and it updates very infrequently. It's basically a slightly elevated UID with adb-level access the apps can use.

  1. 仅支持 IPv4

We can look into it if IPv6 is something people need. I didn't prioritize it, and I can't really test it on my hardware.

  1. 可能在很多设备上被限制

Not really. Only if an OEM makes effort to clean up hidden APIs when making their firmware. They are lazy. I don't think they do. Maybe you know more about the state of the industry?

请问是否总结的到位?

I think it is isolated enough to be easily removable if Android for some reason removes the necessary API. However, since it is probably something they use internally for debugging, I doubt it'll happen in the near future.

I haven't worked on streamlining the main ShizukuTetheringService.kt yet because of late-night bug-hunting. I plan to do it soon. I'll make sure to add more comments to the code to make it clearer what it does.

@eliotcougar

Copy link
Copy Markdown
Contributor Author

We're currently looking for a workaround for API30-32… GPT5.6 is trying one PoC after another on the running emulator right now…

I think we'll have to put Shizuku Tethering behind API33+ gate after all… There was a promising workaround for API32, but it is quite invasive and absolutely not guaranteed to work on anything other than AOSP - creating a tap interface and a Virtual Carrier Network, and then routing tethering traffic through it.
Even GPT thinks it's way too much digging in the Android guts, and it gave me a "Cybersecurity Warning" card.

Use legacy tethering state and stop APIs below Android 16 while retaining the callback-based API 36 path.
Consolidate routing session state and simplify the UI/service synchronization flow to make the feature easier to review and maintain.

Isolate the Android 11-15 and API 36+ tethering calls, as well as the required shell-attribution context bridge, behind focused compatibility helpers. Remove the broad lint suppression, add explicit platform gating, and keep only narrowly documented exceptions for hidden framework APIs.
Move the pure Compose rendering and UI-state mapping into TetheringScreen so ShizukuActivity is limited to lifecycle, permission, binding, and service orchestration responsibilities. This reduces the activity's import surface and makes the feature easier to review while preserving the existing layout and behavior.

Consolidate repeated service-call, operation-state, and hotspot-polling plumbing as part of the split.
Pause active tethering before replacing or removing the Android test network. Reuse the same stop-rebuild-restore ordering for manual recovery and synchronized restarts, and refuse UserService exit when tethering cannot be stopped so clients cannot fall back to an ordinary upstream.
Publish a new synchronization session only after the privileged route starts successfully, restore the previous app token on failure, and reject blank or duplicate starts. Clear a persisted token only when the UserService explicitly reports that the matching session is stale.
Remove the duplicate Wi-Fi status Binder call and use the active tethering-type mask as the single source of truth for status, button state, and polling. Bump the UserService protocol version and add a focused mask-derivation regression test.
Move Android 11-15 reflection, interface classification, and stop polling out of the privileged state machine. Share the Android 11+ start callback with API 36, centralize type masks, and avoid redundant active-state queries during bulk stop and restore operations.
Replace mutually exclusive Xray and HEV strings with a single validated engine payload. Separate initial process-environment setup from restart synchronization so core lifecycle updates no longer compute or carry unused launch data, and cover both config builders with focused tests.
Group the TUN descriptor, framework interface, published network, callback, manager, and Binder lifetime token under one resource owner. Creation now publishes the handle before callbacks can arrive, while cleanup tears down the same captured resource set atomically.
Move Shizuku session lookup, running-core snapshots, and ordered lifecycle broadcasts behind a dedicated coordinator. CoreServiceManager now exposes only start, failure, stop, and snapshot-query integration points, keeping the central core lifecycle easier to review.
Use one positional timeout parser and one escaped YAML builder for the regular VPN and Shizuku tethering engines. Snapshot capture now records the same effective HEV settings used by the primary tunnel, with focused tests for defaults, malformed values, IPv6, and credentials.
Track operation generations so completion from a canceled job cannot overwrite a newer action. Always refresh after the current action finishes or fails, while rethrowing coroutine cancellation instead of converting it into a routing error.
Keep ShizukuActivity focused on lifecycle, permission, binding, and operation orchestration while deriving presentation state in TetheringScreen and consolidating privileged platform behavior behind the service helpers.

Remove dead routing flags and cleanup parameters, avoid duplicate snapshot and broadcast plumbing, and use the shared HEV and engine configuration paths. Reassert the protected test-network preference immediately before tethering starts, refuse unprotected starts, and report Android's real tethering upstream in the UI so an eth0 handover failure is visible instead of being mistaken for the requested test TUN.
Reject core-resynchronization calls below Android 11 before entering the test-network rebuild path, and attach the same platform contract to the private helper. This removes the feature-owned NewApi lint error without suppressing it and makes accidental calls on unsupported releases fail explicitly.
Keep the production refactor commits focused on behavior and structure, then collect their verification coverage in one reviewable follow-up commit.

Cover shared HEV configuration and escaping, native/HEV engine snapshots, legacy tethering type detection, real-upstream status parsing, and Compose control-state behavior including fail-closed waiting states.
Treat Android tethering startup as provisional until the downstream is active and its actual upstream consists only of the owned test TUN. Track in-flight starts so shutdown and failed-start cleanup still stop requests that have not yet appeared in the active type list.

Restart pre-existing downstreams so the test-network preference is applied during upstream selection, reject physical or mixed upstreams immediately, and serialize UI toggles while an operation is pending. Document the Android handover race and teardown invariant for reviewers.
Android 11 and 12 can create the shell-owned test TUN, but the platform does not expose TetheringManager.setPreferTestNetworks in that API range. The VCN substitute we explored depends on carrier privileges and test subscription overrides unavailable to ordinary Shizuku users on production hardware.

Avoid presenting an unreliable, OEM-dependent path. Hide and disable the Tethering UI, receiver, and Shizuku provider below API 33, reject privileged start requests defensively, and remove the now-unreachable unsupported UI state. API 33-35 continue to use the compatibility path while API 36+ keeps the existing implementation.
Restructure the privileged service around smaller lifecycle helpers and document the hidden Android APIs and fail-closed invariants so the implementation is easier to review.

Advertise the app-configured VPN DNS servers on the test network instead of hardcoded resolvers. If Android initially selects a physical upstream, stop the downstream, wait for the framework to settle, and retry once for every tethering type. A persistent mismatch remains disabled and is reported with a localized warning rather than a generic error.
Remove duplicate hotspot and legacy stop polling so the privileged service owns one bounded postcondition check across Android versions.

Reuse the canonical Shizuku manager ID and existing running-profile helper, avoid repeated permission decisions and loading text, and bump the UserService version so stale shell processes are replaced.
Report IPv6 from the real Wi-Fi or USB downstream instead of assuming that enabling IPv6 on the test TUN was sufficient. Map active tethering types to their interface names on Android 13+ and show IPv4-only or IPv4 + IPv6 independently for each active downstream. Keep probe failures distinct from IPv4-only, restart stale Shizuku UserServices after the AIDL change, and localize the diagnostic across every supported app locale.
Replace the full-width enable and disable actions with compact switches in each section header, matching the app's established settings rows. Keep status, diagnostics, and explanatory text in place while preserving the existing guarded toggle behavior for protected tethering and the Wi-Fi hotspot.
@eliotcougar

Copy link
Copy Markdown
Contributor Author

The real-world test succeeded through the whole day of work through USB tethering. All traffic was routed correctly through v2rayNG while using a policyGroup connection.

IPv6 support was added. It seems to be working in the emulator, but I cannot test it because I have no real IPv6 connectivity here.

As a final stroke, I changed the two large buttons into toggle switches like everywhere else in the app. The feature looks more or less complete at this point. I think it is ready.

Delete the localized enable and disable action strings that became unused when the full-width tethering controls were replaced with switches. Preserve the enabled and disabled result messages still used by operation feedback.
Present protected-upstream handover failures as a temporary Android connection switch, with brief wait-and-retry guidance across every supported locale. Align each section icon with its title row and trailing switch while leaving diagnostics and control behavior unchanged.
Present the transient protected-upstream handover notice through the supported info category instead of the retired warning category. Keep the existing localized message and branch base unchanged.
Delete the unreferenced warning toast helpers and enum branch after the transient tethering notice moved to the info category. This also removes the stale snackbar reference to the warning color dropped by the recent UI update.
@eliotcougar

Copy link
Copy Markdown
Contributor Author

Just discovered that starting v2rayNG tethering when there was already an active system tethering shows v2rayNG tethering active, but doesn't actually switch to testtunN interface... The work never ends...

Adopt every downstream already active when protected routing starts by sending it through the existing upstream verification, restart, and single-retry path. A downstream that still cannot select the test TUN is left stopped instead of remaining on its physical upstream.

Reject an unknown initial tethering state and bump the Shizuku UserService version so APK updates replace a long-lived shell process with the corrected implementation.
A control-process failure must never silently route tethered clients outside v2rayNG. Treat loss of either Shizuku or the main core as fail-closed: preserve the dead protected TUN or take the downstream offline instead of allowing Android to select a physical upstream and leak traffic.

Share ownership of the test-network request and TUN descriptor between the normal core and the Shizuku UserService. Track the main-core Binder lifetime so abrupt app death stops the secondary engine while retaining the dead TUN.

When Shizuku returns, receive its replacement Binder in the core process, rebind a fresh UserService, retry once past any stale proxy, and recreate the protected route from the current core snapshot before restoring active downstreams.
The core snapshot response carries the Binder that owns the protected test network and receives its TUN descriptor. Register this receiver as not exported so only another v2rayNG process can provide core state and the lifetime lease, while preserving the existing cross-process synchronization flow.
Android 13-15 expose active downstreams as interface names rather than typed objects. Recognize the standard Wi-Fi P2P, NCM, and Ethernet names, and reject any remaining unknown interface instead of silently dropping it from the safety mask. This keeps the protected test network alive whenever every active downstream cannot be stopped or verified.
The protected-upstream check runs while Android tethering is already active and while the UserService state lock is held. Drain dumpsys output concurrently and enforce a short deadline so a stalled OEM service cannot block leak cleanup, disable requests, or lifecycle recovery indefinitely.
Large custom Xray configurations can exceed Android's shared Binder transaction buffer, especially during profile synchronization. Keep the exact running config in the core process and expose its prepared tethering form through a reliable pipe owned by the existing core lease. Broadcasts and UserService calls now carry only metadata and the Binder handle, while the shell process reads the configuration from the returned file descriptor. Bump the UserService contract version so stale shell processes are replaced.
Reduce review noise in the Shizuku tethering change by narrowing helper visibility, consolidating duplicate core-state resets, and keeping common tethering starts in the existing compatibility path.

Make the Android 16+ helper stop-only, remove unused parameters and package lookup branching, align the drawer list with upstream style, and add precise API guards without lint suppressions. Bump the UserService version so APK updates cannot retain the pre-cleanup shell implementation.
Android 14 and newer can queue Shizuku's cross-process Binder relay while the provider process is cached. The retained test network keeps tethered clients fail-closed, but the shell UserService cannot be recreated until the app becomes active again.

Signal foreground activity resumes to the running core on API 34+, request the replacement Binder once per Shizuku death, and reuse the existing core snapshot synchronization to restore the UserService, secondary engine, and active tethering. Avoid polling and leave Android 13 behavior unchanged.
@eliotcougar

Copy link
Copy Markdown
Contributor Author

Patched a couple of potential (rare, unlikely) traffic-leak scenarios where Android might silently decide to start routing tethered clients traffic directly.
Added automatic tethering recovery from force-closed or crashed Shizuku or v2rayNG apps where it is possible.

Fail-closed enforcement is very important: after the user enables protected routing in the app, until it is disabled, it should either route through the protected testtun interface, or not route at all. There may be more failure scenarios - I'll keep looking.

@vincentng295

Copy link
Copy Markdown

I think this can be a seperated app "Shizuku tether" so it can work with another VPN app not just V2RayNG

@vincentng295

vincentng295 commented Jul 28, 2026

Copy link
Copy Markdown

I suggest request this feature to be added into https://github.com/Mygod/VPNHotspot/issues if possible

@eliotcougar

Copy link
Copy Markdown
Contributor Author

I think this can be a seperated app "Shizuku tether" so it can work with another VPN app not just V2RayNG

The way Android does tethering pass-through to a VPN app (via testtun) makes arbitrary routing unviable. Basically, without root there is not much control over where the testtun binds itself. The current implementation keeps main connection and tethering connection synchronized at all times and allows for strict "fail-closed" operation. Without access to v2rayNG internal states that would be difficult to promise.

Bring the feature branch onto upstream 2.3.1 while retaining Shizuku initialization across the Compose package move and the new launcher and message-helper structure.

Integrate upstream's network-handover core reload with tethering synchronization so the secondary engine pauses before the main core reloads, resumes from the rebuilt configuration, and remains fail-closed if recovery fails. Advance AndroidLibXrayLite and HEV to the revisions selected by upstream.
Sync the feature branch through upstream 2.3.2 and adopt the typed Compose menu actions and Material 3 drawer implementation from 2dust#6016.

Represent Tethering as a MainDestination instead of retaining the legacy string route, preserve its existing API-level resource gate when filtering drawer items, and use the same NavigationDrawerItem path as every other destination. This keeps the feature aligned with upstream without a fork-specific drawer abstraction.
Bring the feature branch through the latest server-editor, UI, and internal asset-storage changes.

Upstream now keeps geodata and user assets in app-private storage, which the shell-owned Shizuku UserService cannot traverse. Expose those files as read-only descriptors through the existing core lifetime lease and stage unchanged assets only once in the shell runtime directory. This preserves native-Xray geoip, geosite, and custom asset routing without weakening the new private-storage boundary.

Bump the UserService contract version so stale shell processes are replaced after the AIDL change.
Bring the feature branch through the centralized per-app locale migration and the latest translation refinements.

Preserve Shizuku AIDL support, provider multiprocess recovery, and foreground fail-closed recovery while adopting AppCompatActivity, AppLocaleManager, generated locale configuration, and localized service contexts.

Keep shell and platform failure diagnostics in logs instead of exposing English exception text through the UI. Live routing still reports the real interface and profile, while error states and toasts use existing localized resources. Bump the UserService version so an older shell process cannot retain the previous presentation behavior.
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.

shizuku support

4 participants