From d4e518c8b8bead98499c74bf3bde989fa74db474 Mon Sep 17 00:00:00 2001 From: "Garry Strait (Chara)" <92406354+GarryStraitYT@users.noreply.github.com> Date: Sat, 27 Jun 2026 11:16:07 -0400 Subject: [PATCH 01/25] Documentation: Updated community-supported-devices.md to bring 1 new device and organization (#222) * Update community-supported devices list This commit adds Motorola Moto G Stylus 5G (2022) [milanf/XT2215] to the list of supported devices. Additionally, it reorganizes the table to be sorted by kernel version instead of whenever the device was added to the list, improving readability and maintenance. Tests performed: None (Documentation update) * Group devices by kernel version in docs Add kernel-version group headers to Documentation/community-supported-devices.md (5.4, 5.10, 5.15, 6.1, 6.6, 6.12) to improve readability and organization of the device compatibility table. Minor table formatting adjustments were made for a few device rows to align them under the new sections. --- Documentation/community-supported-devices.md | 312 ++++++++++--------- 1 file changed, 159 insertions(+), 153 deletions(-) diff --git a/Documentation/community-supported-devices.md b/Documentation/community-supported-devices.md index 9274cb42..4038b3d8 100644 --- a/Documentation/community-supported-devices.md +++ b/Documentation/community-supported-devices.md @@ -26,207 +26,213 @@ This document is a community-maintained compatibility list for Android devices k | Device Name | Model Number | Android / ROM | Baseband / Build | Kernel version | Root Method | Kernel Source | Download Link | Droidspaces Mode | GPU Acceleration | Status | Maintainer | Additional notes | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| **OnePlus 7 Pro** | GM1911 | LineageOS 17.1 - Android 10 | `QQ3A.200805.001` | `4.14.117` | Magisk | [Source](https://github.com/charan-gn/guacamole-droidspaces-kernel) | [Download](https://github.com/charan-gn/guacamole-droidspaces-kernel/releases/tag/v1.0) | Both | Turnip & Virgl | Working | [@charan-gn](https://github.com/charan-gn) | AnyKernel3 flashable on any ROM. | | **Galaxy S10 (Japanese variant)** | SCV41 / SM-G973J | One UI 4.1 - Android 12 | `SCV41KDU1DWC1` | `4.14.190` | KernelSU-Next v3.1.0 | [Source](https://github.com/ravindu644/samsung_kernel_SCV41_droidspaces) | [Download](https://github.com/ravindu644/samsung_kernel_SCV41_droidspaces/releases/download/v2/Droidspaces-KSUN-Samsung-SCV41.tar) | Both | Turnip & Virgl | Working | [@ravindu644](https://github.com/ravindu644) | - | | **Poco X2** | M1912G7Bx | BlissROM-v16.5 - Android 13 | - | `4.14.274` | KernelSU-Next v1.1.1 | [Source](https://github.com/ravindu644/phoenix-blissROM-A13-droidspaces) | [Download](https://github.com/ravindu644/phoenix-blissROM-A13-droidspaces/releases/download/v1/Droidspaces-KSUNv1.1.1-phoenix.zip) | Both | Turnip & Virgl | Working | [@ravindu644](https://github.com/ravindu644) | - | | **Realme 6, 6i, 6s** | RMX2001L1 | RUI 2.0 - Android 11 | - | `4.14.336` | KSU-Next v3.2.0 / ReSukiSU v4.1.0 | [Source](https://github.com/Prime-TITAN-CameraMan/android_kernel_realme_nemo) | [Download](https://github.com/Prime-TITAN-CameraMan/android_kernel_realme_nemo/releases/tag/v1.1) | Both | Virgl | Working | [@Prime-TITAN-CameraMan](https://github.com/Prime-TITAN-CameraMan) | RUI 2.0 only & No Firewall Support (UFW/Fail2ban) | | **Redmi K20 Pro (China)** | M1903F11A | YAAP 16 - Banshee (Android 16) | `1.0.c3-0061-1017_2229_f7c3bc9ce` | `4.14.353` | KernelSU v3.2.4-gee75714a | [Source](https://github.com/Alhkxsj/CRom-KSU-Builder) | [Download](https://github.com/Alhkxsj/CRom-KSU-Builder/releases/download/raphael_YAAP-sixteen_KernelSU-by-xx_20260514_1438/raphael_YAAP-sixteen_KernelSU-by-xx_20260514_1438.zip) | Both | Turnip & Virgl | Working | [@Alhkxsj](https://github.com/Alhkxsj) | Kernel source is stock YAAP kernel; Droidspaces configs applied via automated build workflow | -| **Oneplus 8, 8T, 8Pro, 9R** | IN2010 | Lineage OS 23.2 - Android 16 | `Q_V1_P14` | `4.19.325` | none | [Source](https://github.com/JackA1ltman/dreamworld_oneplus_sm8250) | [Download](https://github.com/JackA1ltman/dreamworld_oneplus_sm8250/releases/tag/v1.2) | Both | Turnip & Virgl | Working | [@JackA1ltman](https://github.com/JackA1ltman) | Custom ROM only. Supported NTSYNC. | -| **OnePlus 7 Pro** | GM1911 | LineageOS 17.1 - Android 10 | `QQ3A.200805.001` | `4.14.117` | Magisk | [Source](https://github.com/charan-gn/guacamole-droidspaces-kernel) | [Download](https://github.com/charan-gn/guacamole-droidspaces-kernel/releases/tag/v1.0) | Both | Turnip & Virgl | Working | [@charan-gn](https://github.com/charan-gn) | AnyKernel3 flashable on any ROM. | | **Redmi note 7 pro (violet)** | M1901F7S | LineagOS 23.2 - Android 16 | `.c2-00029-SM6150_GEN_PACK-1.352094.1.355031.2` | `4.14.357` | Magisk | [source](https://github.com/subhu2008/android_kernel_xiaomi_sm6150) | [Download](https://github.com/subhu2008/android_kernel_xiaomi_sm6150/releases/tag/stable) | Both | Turnip & Virgl | Working | [@subhu2008](https://github.com/subhu2008) | LineageOS 23.2 only. If it works on other AOSP ROM's too, then good. | +| **Oneplus 8, 8T, 8Pro, 9R** | IN2010 | Lineage OS 23.2 - Android 16 | `Q_V1_P14` | `4.19.325` | none | [Source](https://github.com/JackA1ltman/dreamworld_oneplus_sm8250) | [Download](https://github.com/JackA1ltman/dreamworld_oneplus_sm8250/releases/tag/v1.2) | Both | Turnip & Virgl | Working | [@JackA1ltman](https://github.com/JackA1ltman) | Custom ROM only. Supported NTSYNC. | ## GKI Devices (Kernel 5.4 and up) | Device Name | Model Number | Android / ROM | Kernel version | Root Method | Kernel Source | Download Link | Droidspaces Mode | GPU Acceleration | Status | Maintainer | Additional notes | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -| **Galaxy A16 5G** | SM-A166P | One UI 6.1 - Android 14 | `5.15.148` | KernelSU-Next v3.1.0 | [Source](https://github.com/ravindu644/android_kernel_a166p) | [Download](https://github.com/ravindu644/android_kernel_a166p/releases/download/r20260402-c17abb78/KernelSU-SM-A166P-OneUI6-A166PXXS4AYC1-r20260402-c17abb78.tar.zip) | Both | Virgl only | Working | [@ravindu644](https://github.com/ravindu644) | - | -| **Galaxy A16 5G** | SM-A166P | One UI 7.0 - Android 15 | `5.15.167` | KernelSU-Next v1.1.1 | [Source](https://github.com/ravindu644/android_kernel_a166p) | [Download](https://github.com/ravindu644/android_kernel_a166p/releases/download/ubuntu-x-docker/Ubuntu-x-KernelSU-Next-SM-A166P-dev.zip) | Both | Virgl only | Working | [@ravindu644](https://github.com/ravindu644) | - | -| **Galaxy M14 4G** | SM-M145F | One UI 7.0 - Android 15 | `5.15.167` | KernelSU-Next v1.1.1 | [Source](https://github.com/ravindu644/android_kernel_sm_m145f) | [Download](https://github.com/ravindu644/android_kernel_sm_m145f/releases/download/v1/SM-M145F-Droidspaces-KSUNv1.1.1-M145FXXS8DYH1.tar.zip) | Both | Turnip & Virgl | Working | [@ravindu644](https://github.com/ravindu644) | - | -| **Galaxy A25 5G** | SM-A253Z | One UI 8.0 - Android 16 | `5.15.180` | Magisk | [Source](https://github.com/yoshi3jp/android_kernel_samsung_a25ex_mt6835) | [Download](https://github.com/yoshi3jp/android_kernel_samsung_a25ex_mt6835/releases/download/r20260421-89a95a08/DroidSpaces-SM-A253Z-OneUI8-A253ZSCS1BZA2-r20260421-89a95a08.tar.zip) | Both | none | Working | [@yoshi3jp](https://github.com/yoshi3jp) | - | -| **OnePlus Pad 2 Pro (Chinese variant)** | OPD2413 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 3 | -| **OnePlus 13 (Chinese variant)** | PJZ110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | -| **OnePlus 13 (Chinese variant)** | PJZ110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | -| **OnePlus Ace 5 Pro (Chinese variant)** | PKR110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 5 Pro (Chinese variant)** | PKR110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus 13T (Chinese variant)** | PKX110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus 13T (Chinese variant)** | PKX110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 6 (Chinese variant)** | PLR110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 3 Pro (Chinese variant)** | PJX110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 3 Pro (Chinese variant)** | PJX110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 5 (Chinese variant)** | PKG110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 13R | -| **OnePlus Ace 5 (Chinese variant)** | PKG110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 13R | -| **OnePlus 12 (Chinese variant)** | PJD110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | -| **OnePlus 12 (Chinese variant)** | PJD110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | -| **OnePlus Pad Pro (Chinese variant)** | OPD2403 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 2 (International version) | -| **OnePlus Pad Pro (Chinese variant)** | OPD2403 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 2 (International version) | -| **Realme GT 5 Pro (Chinese variant)** | RMX3888 | RealmeUI 7.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus Ace 3 (Chinese variant)** | PJE110 | ColorOS 16.0 - Android 16 | `5.15.180` | none | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_5.15.180_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 12R | -| **OnePlus Ace 3 (Chinese variant)** | PJE110 | ColorOS 15.0 - Android 15 | `5.15.167` | none | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_5.15.167_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 12R | -| **OnePlus Ace 竞速版 (Chinese variant)** | PGZ110 | ColorOS 15.0 - Android 15 | `5.10.167` | Resukisu | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU_oki_5.10.226_Gold_bug_%E5%A4%A9%E7%8E%91%E7%89%B9%E4%BE%9B.zip) | Both | bridge & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **OnePlus SM8650 (All LineageOS OnePlus 6.1 Devices)** | SM8650 | LineageOS 23.2 - Android 16 QPR 2 | `6.1.166` | none | [Source](https://github.com/LineageOS/android_kernel_oneplus_sm8650) | [Download](https://github.com/linx3141/CRom-KSU-Builder/releases/tag/sm8650_LineageOS-lineage-23.2_None_20260512_1647) | Both | Turnip & Virgl | Working | [@linx3141](https://github.com/linx3141) | - | -| **Xiaomi 17 (Chinese variant)** | 25113PN0EC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | -| **Xiaomi 17 Pro (Chinese variant)** | 2509FPN0BC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **Xiaomi 17 Pro max (Chinese variant)** | 25113PN0EC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **红魔 11 Pro (Chinese variant)** | NX809J | RedMagicOS11 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **HONOR Magic Pad 3 Pro 13.3 (Chinese variant)** | YLP-W00 | MagicOS10 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | -| **Xiaomi Pad 7 (Chinese variant)** | 2410CRP4CC | HyperOS 2.0 - Android 15 | `6.1.118` | Sukisu Ultra | [Source](https://github.com/HuangJunLin8/uke_GKI_KernelSU_SUSFS.git) | [Download](https://github.com/HuangJunLin8/uke_GKI_KernelSU_SUSFS/releases/tag/release) | Both | Turnip & Zink | Working | [HuangJunLin8](https://github.com/HuangJunLin8) | Supports NTsync | -| **Xiaomi Pad 8 Pro (Chinese variant)** | 25091RP04C | HyperOS 3.0 - Android 16 | `6.6.77` | Resukisu & NoRoot | [Source](https://github.com/404-GCross/Droidspaces_GKI_Buildin_Local) | [ReSukiSU](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU-34924_6.6.77_NTsync_github@404-GCross.zip)
[NoRoot](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.6.77_NTsync_github@404-GCross.zip) | Both | Turnip & Virgl | Working | [404-GCross](https://github.com/404-GCross) | Applicable to the international version
Supports NTsync
ReSukiSU version 34924 | -| **Xiaomi 15 (Chinese variant)** | 24129PN74C | HyperOS 3.0 - Android 16 | `6.6.77` | Resukisu & NoRoot | [Source](https://github.com/404-GCross/Droidspaces_GKI_Buildin_Local) | [ReSukiSU](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU-34924_6.6.77_NTsync_github@404-GCross.zip)
[NoRoot](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.6.77_NTsync_github@404-GCross.zip) | Both | Turnip & Virgl | Working | [404-GCross](https://github.com/404-GCross) | Applicable to the international version
Supports NTsync
ReSukiSU version 34924 | -| **Xiaomi 14 (Chinese variant)** | 23127PN0CC | HyperOS 3.0 - Android 16 | `6.1.138` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.138_coolapk%40%E7%88%B1%E4%BD%A0%E4%B9%88%E4%B9%88%E5%93%92qcjl%E5%93%9F.zip) | Both | Turnip & Virgl | Working | [爱你么么哒qcjl哟](https://www.coolapk.com/u/29859482) | Applicable to the international version | -| **红魔 9 Pro (Chinese variant)** | NX769J | RedMagicOS11 - Android 16 | `6.1.124` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.124_KPM_BBG_RE-kernel_%E7%BA%A2%E9%AD%949pro_github%40sjszero.zip) | Both | Turnip & Virgl | Working | [@sjszero](https://github.com/sjszero) | - | -| **红魔 9 SPro+ (Chinese variant)** | NX769J | RedMagicOS11 - Android 16 | `6.1.25` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.25_KPM_BBG_RE-kernel_%E7%BA%A2%E9%AD%949spro%2B_github%40sjszero.zip) | Both | Turnip & Virgl | Working | [@sjszero](https://github.com/sjszero) | - | -| **Xiaomi Pad 6S Pro (Chinese variant)** | 24018RPACC | HyperOS 3.0 - Android 16 | `5.15.178` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/Anykernel3_Resukisu_gki_NTsync_5.15.178_github%40mlfc666.zip) | Both | Turnip & Virgl | Working | [@mlfc666](https://github.com/mlfc666) | Applicable to the international version
Supports NTsync | -| **Redmi K70 (Chinese variant)** | 23113RKC6C | HyperOS 3.0 - Android 16 | `5.15.178` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/Anykernel3_Resukisu_gki_NTsync_5.15.178_github%40mlfc666.zip) | Both | Turnip & Virgl | Working | [@mlfc666](https://github.com/mlfc666) | Supports NTsync | -| **Xiaomi Pad 6 Max (yudi)** | 2307BRPDCC | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | -| **Xiaomi Pad 6 Pro (liuqin)** | 2307BRPDCC | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | -| **Redmi K60 / POCO F5 Pro (mondrian)** | 23013RK75C | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | Applicable to the international version -| **Redmi K50 Ultra / Xiaomi 12T Pro (diting)** | 22081212C | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | Applicable to the international version -| **Xiaomi 11T Pro (vili)** | 2107113 | DerpFest A16 | `5.4` | KernelSU-Next | [Source](https://github.com/loystonpais/android_kernel_qcom_sm8350) | [Download](https://github.com/loystonpais/android_kernel_qcom_sm8350/releases/latest) | Both | Turnip & Virgl | Working | [@loystonpais](https://github.com/loystonpais) | - | -| **Redmi Note 13 4G / NFC** | 23124RA7EO | HyperOS 2.0 - Android 15 | `5.15.202` | Wild-KSU v3.1.2 | [Source](https://github.com/superuseryu/kernel_sapphire_SM6225) | [Download](https://github.com/superuseryu/kernel_sapphire_SM6225/releases/tag/v1.5.2%2B_R27) | Both | Turnip | Working | [@superuseryu](https://github.com/superuseryu) | Other KSU variants may fail due to SELinux context reset. | -| **Nothing Phone (1)** | A063 | crDroid - Android 16 | `5.4.302` | KernelSU-Next | [Source](https://github.com/crdroidandroid/android_kernel_nothing_sm7325) | [Download](https://crdroid.net/Spacewar/12) | Both | Turnip & Virgl | Working | [@MySelly](https://github.com/MySelly) | - | +| **5.4 Devices**| - | - | 5.4.x | - | - | - | - | - | - | -| - | | **Reno10 5G** | PHW110 | ColorOS15-16.1 - Android 15-16 | `5.4.254` | ReSukiSU | [Source](https://github.com/miaizhe/Kernel_oppo_sm7325_Reno10) | [Download](https://github.com/miaizhe/Kernel_oppo_sm7325_Reno10/releases) | Both | Turnip | Working | [@miaizhe](https://github.com/miaizhe) | - | +| **Xiaomi 11T Pro (vili)** | 2107113 | DerpFest A16 | `5.4.302` | KernelSU-Next | [Source](https://github.com/loystonpais/android_kernel_qcom_sm8350) | [Download](https://github.com/loystonpais/android_kernel_qcom_sm8350/releases/latest) | Both | Turnip & Virgl | Working | [@loystonpais](https://github.com/loystonpais) | - | +| **Nothing Phone (1)** | A063 | crDroid - Android 16 | `5.4.302` | KernelSU-Next | [Source](https://github.com/crdroidandroid/android_kernel_nothing_sm7325) | [Download](https://crdroid.net/Spacewar/12) | Both | Turnip & Virgl | Working | [@MySelly](https://github.com/MySelly) | - | +| **Motorola Moto G Stylus 5G (2022) | XT2215 | Android 16 QPR2 (LineageOS 23.2 or equivalent) | `5.4.306` | ReSukiSU | [Source](https://github.com/chararomandroid/android_kernel_motorola_sm6375) | [Download](https://github.com/CharaROMAndroid/android_kernel_motorola_sm6375/releases/tag/chaoskernel-milanf) | Both | Turnip | Working | [@GarryStraitYT](https://github.com/GarryStraitYT) | Tested on CharaROM 1.0 Beta 2, should work on any LineageOS 23.2 equivalent. Tested with Retail US variant of XT2215-4 (8GB RAM + 256GB ROM), but should work on any variant. +| **5.10 Devices**| - | - | 5.10.x | - | - | - | - | - | - | -| - | +| **OnePlus Ace 竞速版 (Chinese variant)** | PGZ110 | ColorOS 15.0 - Android 15 | `5.10.167` | Resukisu | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU_oki_5.10.226_Gold_bug_%E5%A4%A9%E7%8E%91%E7%89%B9%E4%BE%9B.zip) | Both | bridge & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 10R** | CPH2411 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_10r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE** | PGKM10 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_ace) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2V** | PHP110 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_oneplus_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE Race** | PGZ110 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_ace_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 3** | CPH2491, CPH2493 | Android14 (OOS/COS 14) | 5.10.198 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_nord_3_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/oneplus/sm8450_u_14.0.0_oneplus_10pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/210ba17c8f19beed0212eb4f209109e35ef35746) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/oneplus/sm8450_v_15.0.0_oneplus_10_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/oneplus/sm8450_b_16.0_oneplus_10_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 10R** | CPH2411 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_10r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10R** | CPH2411 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_v_15.0.0_oneplus_10r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10T** | CPH2415, CPH2413, CPH2417, CPH2419 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/bdebb03938ab5f6719abc50af454d76a1b12df67) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 11R** | CPH2487 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_u_14.0.0_oneplus_11r_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 11R** | CPH2487 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/6821a3751c4fd016a7ee4da5aea635d42a8b3d43) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE** | PGKM10 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/e5f7c2a470fd9d8b43c5082aed8b58a6d5a2bf7c) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2** | PHK110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/ef7ca029d0f6beddf38e60f6b9016935d0f1ac55) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2V** | PHP110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/8a49e1e297768839d78730f15e8f34e0d0b59f2b) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/7a64b08a000cc7040d99543cc7093aaa13e0c786) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 3** | CPH2491, CPH2493 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/b9b40be7bbe4e2c201ba263ac72f2e1b10171998) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Go** | OPD2304, OPD2305 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_u_14.0.0_onepluspad_go) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad MT6983** | OPD2203 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad MT6983** | OPD2203 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/4790201712d757f4f337cd55e5709255edc8bee5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/oneplus/sm8450_v_15.0.0_oneplus_10_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10T** | CPH2415, CPH2413, CPH2417, CPH2419 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/45235533105840dc875a80e9d5b4cd881e453472) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 11R** | CPH2487 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_v_15.0.0_oneplus_11r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE** | PGKM10 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_v_15.0.0_ace) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2** | PHK110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_v_15.0.0_ace_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2V** | PHP110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/6409af87cfda3739caff4ee29eb28e77abe8a290) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 3** | CPH2491, CPH2493 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_nord_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Lite** | OPD2480, OPD2481 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_v_15.0.1_pad_lite) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad MT6983** | OPD2203 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 10 Pro** | NE2210, NE2211, NE2213, NE2215, NE2217 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8450/tree/oneplus/sm8450_b_16.0_oneplus_10_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 10T** | CPH2415, CPH2413, CPH2417, CPH2419 | Android15 (OOS/COS 15) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_v_15.0.0_oneplus_10t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 11R** | CPH2487 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_b_16.0.0_oneplus_11r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2** | PHK110 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_b_16.0.0_ace_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2V** | PHP110 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_b_16.0.0_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_v_15.0.0_ace_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad MT6983** | OPD2203 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_b_16.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Xiaomi Pad 6 Max (yudi)** | 2307BRPDCC | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | +| **Xiaomi Pad 6 Pro (liuqin)** | 2307BRPDCC | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | +| **Redmi K60 / POCO F5 Pro (mondrian)** | 23013RK75C | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | Applicable to the international version | +| **Redmi K50 Ultra / Xiaomi 12T Pro (diting)** | 22081212C | HyperOS 3.0 - Android 15 | `5.10.252` | none | [Source](https://github.com/Star-ZER0/android_gki_kernel_5.10_common) | [Download](https://github.com/Star-ZER0/android_gki_kernel_5.10_common/releases/latest) | Both | Turnip & Virgl | Working | [@Star-ZER0](https://github.com/Star-ZER0) | Supports NTsync | Applicable to the international version | +| **5.15 Devices** | - | - | 5.15.x | - | - | - | - | - | - | -| - | | **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android14 (OOS/COS 14) | 5.15.123 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_u_14.0.0_oneplus11) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Galaxy A16 5G** | SM-A166P | One UI 6.1 - Android 14 | `5.15.148` | KernelSU-Next v3.1.0 | [Source](https://github.com/ravindu644/android_kernel_a166p) | [Download](https://github.com/ravindu644/android_kernel_a166p/releases/download/r20260402-c17abb78/KernelSU-SM-A166P-OneUI6-A166PXXS4AYC1-r20260402-c17abb78.tar.zip) | Both | Virgl only | Working | [@ravindu644](https://github.com/ravindu644) | - | | **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/7d9f64c901ac11ce80bf78682d33fd336c825fd9) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/86a89359565410962004fd838e3d2e3b42a047ca) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2 Pro** | PJA110 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/95b9da8a7cd99053f65e7d4cebec310b5f5d5744) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 3** | PJE110 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/3a51ce558bfa3a1c7eeaaab69ee54d5e6bd03afb) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/d8187f64c9e60fee0969a678a67ac77114a926d9) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Open** | CPH2551 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/2a845b8afd7afc3d72679ddbe5adb07c390966bc) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Galaxy A16 5G** | SM-A166P | One UI 7.0 - Android 15 | `5.15.167` | KernelSU-Next v1.1.1 | [Source](https://github.com/ravindu644/android_kernel_a166p) | [Download](https://github.com/ravindu644/android_kernel_a166p/releases/download/ubuntu-x-docker/Ubuntu-x-KernelSU-Next-SM-A166P-dev.zip) | Both | Virgl only | Working | [@ravindu644](https://github.com/ravindu644) | - | +| **Galaxy M14 4G** | SM-M145F | One UI 7.0 - Android 15 | `5.15.167` | KernelSU-Next v1.1.1 | [Source](https://github.com/ravindu644/android_kernel_sm_m145f) | [Download](https://github.com/ravindu644/android_kernel_sm_m145f/releases/download/v1/SM-M145F-Droidspaces-KSUNv1.1.1-M145FXXS8DYH1.tar.zip) | Both | Turnip & Virgl | Working | [@ravindu644](https://github.com/ravindu644) | - | +| **OnePlus Ace 3 (Chinese variant)** | PJE110 | ColorOS 15.0 - Android 15 | `5.15.167` | none | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_5.15.167_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 12R | | **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_oneplus11) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android16 (OOS/COS 16) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/bee3255be1f407e7cff7b0b8f1c26daaccbbb510) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_11) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 11R** | CPH2487 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_u_14.0.0_oneplus_11r_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 11R** | CPH2487 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/6821a3751c4fd016a7ee4da5aea635d42a8b3d43) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 11R** | CPH2487 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_v_15.0.0_oneplus_11r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 11R** | CPH2487 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_b_16.0.0_oneplus_11r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android14 (OOS/COS 14) | 6.1.57 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_u_14.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/c461b745bc361581d0b419effd284367d85f1e57) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/2936373a255da66646a05384e993d55a8dfecc80) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/86a89359565410962004fd838e3d2e3b42a047ca) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_oneplus_12r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android16 (OOS/COS 16) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/717aea450444dfd00db7d60c99cff77fbcbf014e) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_12r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13** | CPH2655, CPH2653, PJZ110, CPH2649 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/f9c1a38fe1bf6bf39f25e4167e8322813c7707b9) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13** | CPH2655, CPH2653, PJZ110, CPH2649 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13 CPH** | CPH2655, CPH2653, CPH2649 | Android15 (OOS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/cec4a1056a32dfdd68c23767f6c88bb6c698f1bf) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13 CPH** | CPH2655, CPH2653, CPH2649 | Android15 (OOS 15) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_13_global) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13 PJZ** | PJZ110 | Android15 (COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_13) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/d68f486cb00b246abf4b7b66375082dc8bcb884e) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_oneplus_13r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/35f7c28cf36e19e3243a9db8496d5e70b94e34ce) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_oneplus_13r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13S** | CPH2723 | Android15 (OOS/COS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.2_oneplus_13s) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13S** | CPH2723 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13s) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13T** | PKX110 | Android15 (OOS/COS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/06be241a7b9eefa01db78447cc7877339b3685f3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13T** | PKX110 | Android15 (OOS/COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.2_oneplus_13t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 13T** | PKX110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 15** | CPH2747, CPH2745, PLK110, CPH2749 | Android16 (OOS/COS 16) | 6.12.23 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0.0_oneplus_15) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 15R** | CPH2769, CPH2767 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8845/tree/oneplus/sm8845_b_16.0.0_oneplus_15r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus 15T** | PLZ110 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_oneplus_15t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE** | PGKM10 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_ace) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE** | PGKM10 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/e5f7c2a470fd9d8b43c5082aed8b58a6d5a2bf7c) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE** | PGKM10 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_v_15.0.0_ace) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2** | PHK110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/ef7ca029d0f6beddf38e60f6b9016935d0f1ac55) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2** | PHK110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_v_15.0.0_ace_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2** | PHK110 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8475/tree/oneplus/sm8475_b_16.0.0_ace_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2 Pro** | PJA110 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/95b9da8a7cd99053f65e7d4cebec310b5f5d5744) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 2 Pro** | PJA110 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_ace_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2 Pro** | PJA110 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_ace_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2V** | PHP110 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_oneplus_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2V** | PHP110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/8a49e1e297768839d78730f15e8f34e0d0b59f2b) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2V** | PHP110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 2V** | PHP110 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_b_16.0.0_ace_2v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 3** | PJE110 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/3a51ce558bfa3a1c7eeaaab69ee54d5e6bd03afb) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3** | PJE110 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_ace_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3** | PJE110 | Android16 (OOS/COS 16) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/3dc000f085497a728cdf21b28fab9d3ef632f5fd) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/0d28103245225a507d4f4b3ca657d3e27aae2f20) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Open** | CPH2551 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_oneplus_open) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Open** | CPH2551 | Android16 (OOS/COS 16) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/1e88584a40b3b055e5ff3796f9a184655ef2d0b8) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Xiaomi Pad 6S Pro (Chinese variant)** | 24018RPACC | HyperOS 3.0 - Android 16 | `5.15.178` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/Anykernel3_Resukisu_gki_NTsync_5.15.178_github%40mlfc666.zip) | Both | Turnip & Virgl | Working | [@mlfc666](https://github.com/mlfc666) | Applicable to the international version
Supports NTsync | +| **Redmi K70 (Chinese variant)** | 23113RKC6C | HyperOS 3.0 - Android 16 | `5.15.178` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/Anykernel3_Resukisu_gki_NTsync_5.15.178_github%40mlfc666.zip) | Both | Turnip & Virgl | Working | [@mlfc666](https://github.com/mlfc666) | Supports NTsync | +| **Galaxy A25 5G** | SM-A253Z | One UI 8.0 - Android 16 | `5.15.180` | Magisk | [Source](https://github.com/yoshi3jp/android_kernel_samsung_a25ex_mt6835) | [Download](https://github.com/yoshi3jp/android_kernel_samsung_a25ex_mt6835/releases/download/r20260421-89a95a08/DroidSpaces-SM-A253Z-OneUI8-A253ZSCS1BZA2-r20260421-89a95a08.tar.zip) | Both | none | Working | [@yoshi3jp](https://github.com/yoshi3jp) | - | +| **OnePlus Ace 3 (Chinese variant)** | PJE110 | ColorOS 16.0 - Android 16 | `5.15.180` | none | [Source](https://github.com/Numbersf/Action-Build) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_5.15.180_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 12R | +| **OnePlus 11** | PHB110, CPH2449, CPH2447, CPH2451 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_11) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 12R** | CPH2609, CPH2585, CPH2611 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_12r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 2 Pro** | PJA110 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_ace_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3** | PJE110 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_ace_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/oneplus/sm7550_v_15.0.0_nord_ce4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4 CE** | CPH2613 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/oneplus/sm7550_b_16.0.0_nord_ce4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Open** | CPH2551 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_open) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Redmi Note 13 4G / NFC** | 23124RA7EO | HyperOS 2.0 - Android 15 | `5.15.202` | Wild-KSU v3.1.2 | [Source](https://github.com/superuseryu/kernel_sapphire_SM6225) | [Download](https://github.com/superuseryu/kernel_sapphire_SM6225/releases/tag/v1.5.2%2B_R27) | Both | Turnip | Working | [@superuseryu](https://github.com/superuseryu) | Other KSU variants may fail due to SELinux context reset. | +| **6.1 Devices** | - | - | 6.1.x | - | - | - | - | - | - | -| - | +| **红魔 9 SPro+ (Chinese variant)** | NX769J | RedMagicOS11 - Android 16 | `6.1.25` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.25_KPM_BBG_RE-kernel_%E7%BA%A2%E9%AD%949spro%2B_github%40sjszero.zip) | Both | Turnip & Virgl | Working | [@sjszero](https://github.com/sjszero) | - | +| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android14 (OOS/COS 14) | 6.1.57 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_u_14.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/c461b745bc361581d0b419effd284367d85f1e57) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/d68f486cb00b246abf4b7b66375082dc8bcb884e) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3 Pro** | PJX110 | Android14 (OOS/COS 14) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_u_14.1.0_oneplus_ace3pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3 Pro** | PJX110 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/1cee682fb60cc9ffd86a2342fa8051bcde77116f) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 3V** | PJF110 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/ac51a5e4c2b0f13f06e9234e415bfa68fb24a8b5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5** | PKG110 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/8c797fd3ff3f76248b44a619410ace1277692907) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4** | CPH2663, CPH2661 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/a3c5659c859e888102a144be0884fbf3731b170f) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord CE4 Lite** | CPH2619, CPH2621 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm6375/tree/oneplus/sm6375_v_15.0.0_nord_ce4_lite_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 2 SM8650** | OPD2403 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/f5a170ce44c7657894247de3de41d23a89e248f7) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 3 MT6897** | OPD2407 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/cbae97472bca105f69ffaef126065f9ab06e1c12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Pro** | OPD2404 | Android14 (OOS/COS 14) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_u_14.1.0_onepluspad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Pro** | OPD2404 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/dcb47d3dcba84e13ae678f18b4629b22333e8898) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Yoga Tab Plus (International variant)** | TB520FU | ZUI 17.5.10.096 (ROW) - Android14 | `6.1.112` | SukiSU-Ultra v4.1.3 (40796) | [Source](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki) | [Download](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki/releases/download/v1.0.0/tb520fu-droidspaces-phase2-images.zip) | Both | Turnip | Partial | [@da-ai-xian-zun](https://github.com/da-ai-xian-zun) | Maintainer path verified with **locked bootloader** via 9008 four-image manual flash (not AnyKernel3), see [MANUAL_FLASH.md](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki/blob/main/docs/MANUAL_FLASH.md); verified on this ZUI build (ROW, `UKQ1.240826.001`) only—bundled `init_boot`/`vbmeta` are tied to this AVB chain; if bootloader is unlocked, use fastboot with your own `init_boot`/vbmeta for looser AVB constraints; use directory mode for containers; App sparse install unresolved; VirGL not tested | +| **OnePlus ACE 5 Racing** | PLF110 | Android15 (OOS/COS 15) | 6.1.115 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6989/tree/oneplus/mt6989_v_15.0.2_ace5_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord CE5** | CPH2719, CPH2717 | Android15 (OOS/COS 15) | 6.1.115 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_v_15.0.2_nord_ce5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Ace 3 Pro (Chinese variant)** | PJX110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus Ace 5 (Chinese variant)** | PKG110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 13R | +| **OnePlus 12 (Chinese variant)** | PJD110 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | +| **OnePlus Pad Pro (Chinese variant)** | OPD2403 | ColorOS 16.0 - Android 16 | `6.1.118` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 2 (International version) | +| **Xiaomi Pad 7 (Chinese variant)** | 2410CRP4CC | HyperOS 2.0 - Android 15 | `6.1.118` | Sukisu Ultra | [Source](https://github.com/HuangJunLin8/uke_GKI_KernelSU_SUSFS.git) | [Download](https://github.com/HuangJunLin8/uke_GKI_KernelSU_SUSFS/releases/tag/release) | Both | Turnip & Zink | Working | [HuangJunLin8](https://github.com/HuangJunLin8) | Supports NTsync | +| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/2936373a255da66646a05384e993d55a8dfecc80) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_oneplus_13r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/35f7c28cf36e19e3243a9db8496d5e70b94e34ce) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3 Pro** | PJX110 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_ace_3_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3 Pro** | PJX110 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_ace_3_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 3V** | PJF110 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/ac51a5e4c2b0f13f06e9234e415bfa68fb24a8b5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3V** | PJF110 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_v_15.0.0_ace_3v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 3V** | PJF110 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/65c3035422d899d95bfde4e30dc426712ffe52f2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 3V** | PJF110 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_b_16.0.0_ace_3v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5** | PKG110 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/8c797fd3ff3f76248b44a619410ace1277692907) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 5** | PKG110 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_oneplus_ace5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus ACE 5** | PKG110 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/7499247fd6e0669a062ec44cce948ec1e9d4c75e) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5** | PKG110 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_ace_5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Pro** | PKR110 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/94969654b1ac03071c42c4757cd9333535612415) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Pro** | PKR110 | Android15 (OOS/COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_ace5_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Pro** | PKR110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_ace5_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Racing** | PLF110 | Android15 (OOS/COS 15) | 6.1.115 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6989/tree/oneplus/mt6989_v_15.0.2_ace5_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Racing** | PLF110 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6989/tree/oneplus/mt6989_b_16.0.0_ace5_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Ultra** | PLC110 | Android15 (OOS/COS 15) | 6.6.50 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/06b1dfbb8f777d329a25d6f932f58f0e45d87627) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Ultra** | PLC110 | Android15 (OOS/COS 15) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_v_15.0.2_ace5_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 5 Ultra** | PLC110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_b_16.0.0_oneplus_ace5_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 6** | PLQ110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_ace_6) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 6 Ultra** | PMB110 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6993/tree/oneplus/mt6993_b_16.0_ace_6_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE 6T** | PLR110 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8845/tree/oneplus/sm8845_b_16.0.0_ace_6t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE Race** | PGZ110 | Android14 (OOS/COS 14) | 5.10.168 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_u_14.0.0_ace_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/7a64b08a000cc7040d99543cc7093aaa13e0c786) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/6409af87cfda3739caff4ee29eb28e77abe8a290) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus ACE Race** | PGZ110 | Android15 (OOS/COS 15) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6895/tree/oneplus/mt6895_v_15.0.0_ace_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 3** | CPH2491, CPH2493 | Android14 (OOS/COS 14) | 5.10.198 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_nord_3_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 3** | CPH2491, CPH2493 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/b9b40be7bbe4e2c201ba263ac72f2e1b10171998) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 3** | CPH2491, CPH2493 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_nord_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4** | CPH2663, CPH2661 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/a3c5659c859e888102a144be0884fbf3731b170f) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Nord 4** | CPH2663, CPH2661 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_v_15.0.0_nord_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Nord 4** | CPH2663, CPH2661 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/975bcbc2e288c3b7c2d2799421c7f356f9c78ce4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4** | CPH2663, CPH2661 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_b_16.0.0_nord_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/d8187f64c9e60fee0969a678a67ac77114a926d9) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/0d28103245225a507d4f4b3ca657d3e27aae2f20) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4 CE** | CPH2613 | Android15 (OOS/COS 15) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/oneplus/sm7550_v_15.0.0_nord_ce4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 4 CE** | CPH2613 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7550/tree/oneplus/sm7550_b_16.0.0_nord_ce4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Nord 5** | CPH2709, CPH2707 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8635/tree/oneplus/sm8635_v_15.0.2_nord5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Nord 5** | CPH2709, CPH2707 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8635/tree/fbeaa9ff25bef199618b9e47004f2eb8fe135f9f) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 5** | CPH2709, CPH2707 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8635/tree/oneplus/sm8635_b_16.0.0_nord_5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord 6** | CPH2793, CPH2795 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8735/tree/oneplus/sm8735_b_16.0.0_nord_6) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord CE4 Lite** | CPH2619, CPH2621 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm6375/tree/oneplus/sm6375_v_15.0.0_nord_ce4_lite_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Nord CE4 Lite** | CPH2619, CPH2621 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm6375/tree/oneplus/sm6375_b_16.0.0_nord_ce4_lite_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord CE5** | CPH2719, CPH2717 | Android15 (OOS/COS 15) | 6.1.115 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_v_15.0.2_nord_ce5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord CE5** | CPH2719, CPH2717 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_b_16.0.0_nord_ce5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Nord N30 SE** | CPH2605 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6833/tree/oneplus/mt6833_v_15.0.0_nord_n30_se_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Open** | CPH2551 | Android15 (OOS/COS 15) | 5.15.149 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/2a845b8afd7afc3d72679ddbe5adb07c390966bc) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Open** | CPH2551 | Android15 (OOS/COS 15) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_v_15.0.0_oneplus_open) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Open** | CPH2551 | Android16 (OOS/COS 16) | 5.15.167 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/1e88584a40b3b055e5ff3796f9a184655ef2d0b8) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Open** | CPH2551 | Android16 (OOS/COS 16) | 5.15.180 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8550/tree/oneplus/sm8550_b_16.0.0_oneplus_open) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 2 MT6991** | OPD2508 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_b_16.0.0_pad_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 2 Pro** | OPD2413 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/68c46d941cc1818d49f8a8805c79e63fbee01eac) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 2 Pro** | OPD2413 | Android15 (OOS/COS 15) | 6.6.57 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.1_pad_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 2 Pro** | OPD2413 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_pad_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 2 SM8650** | OPD2403 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/f5a170ce44c7657894247de3de41d23a89e248f7) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 2 SM8650** | OPD2403 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_pad2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 2 SM8650** | OPD2403 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_pad2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 3 MT6897** | OPD2407 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/cbae97472bca105f69ffaef126065f9ab06e1c12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Pro** | OPD2404 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_pad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Pro** | OPD2404 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_pad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Turbo 6V** | PLY110 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7635/tree/oneplus/sm7635_b_16.0.0_turbo_6v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **红魔 9 Pro (Chinese variant)** | NX769J | RedMagicOS11 - Android 16 | `6.1.124` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.124_KPM_BBG_RE-kernel_%E7%BA%A2%E9%AD%949pro_github%40sjszero.zip) | Both | Turnip & Virgl | Working | [@sjszero](https://github.com/sjszero) | - | | **OnePlus Pad 3 MT6897** | OPD2407 | Android15 (OOS/COS 15) | 6.1.128 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_v_15.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Racing** | PLF110 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6989/tree/oneplus/mt6989_b_16.0.0_ace5_race) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord CE5** | CPH2719, CPH2717 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_b_16.0.0_nord_ce5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 3 MT6897** | OPD2407 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6897/tree/oneplus/mt6897_b_16.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 3 Pro** | OPD2513 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_3_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Go 2** | OPD2504, OPD2505 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6878/tree/oneplus/mt6878_b_16.0.0_pad_go_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Xiaomi 14 (Chinese variant)** | 23127PN0CC | HyperOS 3.0 - Android 16 | `6.1.138` | Resukisu | [Source](https://github.com/zzh20188/GKI_KernelSU_SUSFS) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_Resukisu_gki_6.1.138_coolapk%40%E7%88%B1%E4%BD%A0%E4%B9%88%E4%B9%88%E5%93%92qcjl%E5%93%9F.zip) | Both | Turnip & Virgl | Working | [爱你么么哒qcjl哟](https://www.coolapk.com/u/29859482) | Applicable to the international version | +| **OnePlus Ace 3 Pro (Chinese variant)** | PJX110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus Ace 5 (Chinese variant)** | PKG110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus 13R | +| **OnePlus 12 (Chinese variant)** | PJD110 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | +| **OnePlus Pad Pro (Chinese variant)** | OPD2403 | ColorOS 16.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.141_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 2 (International version) | +| **Realme GT 5 Pro (Chinese variant)** | RMX3888 | RealmeUI 7.0 - Android 16 | `6.1.141` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8650) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.1.118_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 12** | PJD110, CPH2573, CPH2581, CPH2583 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_oneplus12) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13R** | CPH2645, CPH2691, CPH2647 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_oneplus_13r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 3V** | PJF110 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_b_16.0.0_ace_3v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5** | PKG110 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_ace_5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 4** | CPH2663, CPH2661 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7675/tree/oneplus/sm7675_b_16.0.0_nord_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 5** | CPH2709, CPH2707 | Android16 (OOS/COS 16) | 6.1.141 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8635/tree/oneplus/sm8635_b_16.0.0_nord_5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus SM8650 (All LineageOS OnePlus 6.1 Devices)** | SM8650 | LineageOS 23.2 - Android 16 QPR 2 | `6.1.166` | none | [Source](https://github.com/LineageOS/android_kernel_oneplus_sm8650) | [Download](https://github.com/linx3141/CRom-KSU-Builder/releases/tag/sm8650_LineageOS-lineage-23.2_None_20260512_1647) | Both | Turnip & Virgl | Working | [@linx3141](https://github.com/linx3141) | - | +| **6.6 Devices** | - | - | 6.6.x | - | - | - | - | - | - | -| - | +| **OnePlus 13** | CPH2655, CPH2653, PJZ110, CPH2649 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/f9c1a38fe1bf6bf39f25e4167e8322813c7707b9) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Pro** | PKR110 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/94969654b1ac03071c42c4757cd9333535612415) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord N30 SE** | CPH2605 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6833/tree/oneplus/mt6833_v_15.0.0_nord_n30_se_5g) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 2 Pro** | OPD2413 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/68c46d941cc1818d49f8a8805c79e63fbee01eac) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 3 SM8750** | OPD2415 | Android15 (OOS/COS 15) | 6.6.30 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/35366be96d7e73d1d0d7093e1cf2fafd58f9c7d4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Ultra** | PLC110 | Android15 (OOS/COS 15) | 6.6.50 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/06b1dfbb8f777d329a25d6f932f58f0e45d87627) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13 CPH** | CPH2655, CPH2653, CPH2649 | Android15 (OOS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/cec4a1056a32dfdd68c23767f6c88bb6c698f1bf) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13S** | CPH2723 | Android15 (OOS/COS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.2_oneplus_13s) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13T** | PKX110 | Android15 (OOS/COS 15) | 6.6.56 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/06be241a7b9eefa01db78447cc7877339b3685f3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 2 Pro** | OPD2413 | Android15 (OOS/COS 15) | 6.6.57 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.1_pad_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 3 SM8750** | OPD2415 | Android15 (OOS/COS 15) | 6.6.57 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.1_pad_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13 (Chinese variant)** | PJZ110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | +| **OnePlus Ace 5 Pro (Chinese variant)** | PKR110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 13T (Chinese variant)** | PKX110 | ColorOS 15.0 - Android 15 | `6.6.66` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.66_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 13 PJZ** | PJZ110 | Android15 (COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_13) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13T** | PKX110 | Android15 (OOS/COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.2_oneplus_13t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Pro** | PKR110 | Android15 (OOS/COS 15) | 6.6.66 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_ace5_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Xiaomi Pad 8 Pro (Chinese variant)** | 25091RP04C | HyperOS 3.0 - Android 16 | `6.6.77` | Resukisu & NoRoot | [Source](https://github.com/404-GCross/Droidspaces_GKI_Buildin_Local) | [ReSukiSU](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU-34924_6.6.77_NTsync_github@404-GCross.zip)
[NoRoot](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.6.77_NTsync_github@404-GCross.zip) | Both | Turnip & Virgl | Working | [404-GCross](https://github.com/404-GCross) | Applicable to the international version
Supports NTsync
ReSukiSU version 34924 | +| **Xiaomi 15 (Chinese variant)** | 24129PN74C | HyperOS 3.0 - Android 16 | `6.6.77` | Resukisu & NoRoot | [Source](https://github.com/404-GCross/Droidspaces_GKI_Buildin_Local) | [ReSukiSU](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_ReSukiSU-34924_6.6.77_NTsync_github@404-GCross.zip)
[NoRoot](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.6.77_NTsync_github@404-GCross.zip) | Both | Turnip & Virgl | Working | [404-GCross](https://github.com/404-GCross) | Applicable to the international version
Supports NTsync
ReSukiSU version 34924 | +| **OnePlus Pad 2 Pro (Chinese variant)** | OPD2413 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Suitable for OnePlus Pad 3 | +| **OnePlus 13 (Chinese variant)** | PJZ110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | +| **OnePlus Ace 5 Pro (Chinese variant)** | PKR110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 13T (Chinese variant)** | PKX110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus Ace 6 (Chinese variant)** | PLR110 | ColorOS 16.0 - Android 16 | `6.6.89` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8750) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/OKI%E5%86%85%E6%A0%B8/AnyKernel3_oki_6.6.89_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 13** | CPH2655, CPH2653, PJZ110, CPH2649 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13 CPH** | CPH2655, CPH2653, CPH2649 | Android15 (OOS 15) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_v_15.0.0_oneplus_13_global) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13S** | CPH2723 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13s) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 13T** | PKX110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_13t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Pro** | PKR110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_oneplus_ace5_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Ultra** | PLC110 | Android15 (OOS/COS 15) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_v_15.0.2_ace5_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 5 Ultra** | PLC110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_b_16.0.0_oneplus_ace5_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 6** | PLQ110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_ace_6) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Nord 6** | CPH2793, CPH2795 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8735/tree/oneplus/sm8735_b_16.0.0_nord_6) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 2 MT6991** | OPD2508 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6991/tree/oneplus/mt6991_b_16.0.0_pad_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 2 Pro** | OPD2413 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_pad_2_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 3 SM8750** | OPD2415 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8750/tree/oneplus/sm8750_b_16.0.0_pad_3) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad 4** | OPD2514 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Go** | OPD2304, OPD2305 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_u_14.0.0_onepluspad_go) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Go 2** | OPD2504, OPD2505 | Android16 (OOS/COS 16) | 6.1.134 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6878/tree/oneplus/mt6878_b_16.0.0_pad_go_2) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Lite** | OPD2480, OPD2481 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_v_15.0.1_pad_lite) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Lite** | OPD2480, OPD2481 | Android16 (OOS/COS 16) | 6.12.23 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_b_16.0_pad_lite) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad MT6983** | OPD2203 | Android14 (OOS/COS 14) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus_mt6983_u_14.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad MT6983** | OPD2203 | Android15 (OOS/COS 15) | 5.10.209 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/4790201712d757f4f337cd55e5709255edc8bee5) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad MT6983** | OPD2203 | Android15 (OOS/COS 15) | 5.10.226 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_v_15.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad MT6983** | OPD2203 | Android16 (OOS/COS 16) | 5.10.236 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_5.10_oneplus_mt6983/tree/oneplus/mt6983_b_16.0.0_oneplus_pad) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Pro** | OPD2404 | Android14 (OOS/COS 14) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_u_14.1.0_onepluspad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Pro** | OPD2404 | Android15 (OOS/COS 15) | 6.1.75 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/dcb47d3dcba84e13ae678f18b4629b22333e8898) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Pro** | OPD2404 | Android15 (OOS/COS 15) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_v_15.0.0_pad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Pad Pro** | OPD2404 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8650/tree/oneplus/sm8650_b_16.0.0_pad_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Turbo 6** | PLU110 | Android16 (OOS/COS 16) | 6.6.89 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8735/tree/oneplus/sm8735_b_16.0.0_turbo_6) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **OnePlus Turbo 6V** | PLY110 | Android16 (OOS/COS 16) | 6.1.118 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm7635/tree/oneplus/sm7635_b_16.0.0_turbo_6v) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | -| **Yoga Tab Plus (International variant)** | TB520FU | ZUI 17.5.10.096 (ROW) - Android14 | `6.1.112` | SukiSU-Ultra v4.1.3 (40796) | [Source](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki) | [Download](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki/releases/download/v1.0.0/tb520fu-droidspaces-phase2-images.zip) | Both | Turnip | Partial | [@da-ai-xian-zun](https://github.com/da-ai-xian-zun) | Maintainer path verified with **locked bootloader** via 9008 four-image manual flash (not AnyKernel3), see [MANUAL_FLASH.md](https://github.com/da-ai-xian-zun/tb520fu-droidspaces-gki/blob/main/docs/MANUAL_FLASH.md); verified on this ZUI build (ROW, `UKQ1.240826.001`) only—bundled `init_boot`/`vbmeta` are tied to this AVB chain; if bootloader is unlocked, use fastboot with your own `init_boot`/vbmeta for looser AVB constraints; use directory mode for containers; App sparse install unresolved; VirGL not tested | - +| **6.12 Devices** | - | - | 6.12.x | - | - | - | - | - | - | -| - | +| **Xiaomi 17 (Chinese variant)** | 25113PN0EC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | Applicable to the international version | +| **Xiaomi 17 Pro (Chinese variant)** | 2509FPN0BC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **Xiaomi 17 Pro max (Chinese variant)** | 25113PN0EC | HyperOS 3.0 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **红魔 11 Pro (Chinese variant)** | NX809J | RedMagicOS11 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **HONOR Magic Pad 3 Pro 13.3 (Chinese variant)** | YLP-W00 | MagicOS10 - Android 16 | `6.12.23` | none | [Source](https://github.com/cctv18/oppo_oplus_realme_sm8850) | [Download](https://raw.githubusercontent.com/Goldzxcbug/Droidspaces-kernel/refs/heads/main/GKI%E5%86%85%E6%A0%B8/AnyKernel3_gki_6.12.23_Gold_bug.zip) | Both | Turnip & Virgl | Working | [@Goldzxcbug](https://github.com/Goldzxcbug) | - | +| **OnePlus 15** | CPH2747, CPH2745, PLK110, CPH2749 | Android16 (OOS/COS 16) | 6.12.23 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0.0_oneplus_15) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad Lite** | OPD2480, OPD2481 | Android16 (OOS/COS 16) | 6.12.23 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6789/tree/oneplus/mt6789_b_16.0_pad_lite) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 15R** | CPH2769, CPH2767 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8845/tree/oneplus/sm8845_b_16.0.0_oneplus_15r) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus 15T** | PLZ110 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_oneplus_15t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 6T** | PLR110 | Android16 (OOS/COS 16) | 6.12.38 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8845/tree/oneplus/sm8845_b_16.0.0_ace_6t) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus ACE 6 Ultra** | PMB110 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6993/tree/oneplus/mt6993_b_16.0_ace_6_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 3 Pro** | OPD2513 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_3_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **OnePlus Pad 4** | OPD2514 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | ## Contribution guidelines To keep this list useful and reliable, please follow these rules when adding or updating entries: From bc6c536a7187a33de9829057c87e5bfd42d31ebc Mon Sep 17 00:00:00 2001 From: Jesse205 <51242302+Jesse205@users.noreply.github.com> Date: Mon, 29 Jun 2026 00:15:38 +0800 Subject: [PATCH 02/25] docs: remove garbled characters from the Android installation guide (#223) --- Documentation/zh-CN/Installation-Android.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/zh-CN/Installation-Android.md b/Documentation/zh-CN/Installation-Android.md index 70efd76c..da72811e 100644 --- a/Documentation/zh-CN/Installation-Android.md +++ b/Documentation/zh-CN/Installation-Android.md @@ -67,7 +67,7 @@ Droidspaces 在 Android 上旨在提供"零终端"体验。从首次安装到运 你可以随时验证系统状态: 1. 前往**设置**(齿轮图标)-> **需求**。 2. 点击**检查需求**。这会在内部运行完整的 `droidspaces check` 套件。 -3. **内核配置**:如果你是一位内核开发者,你可以找到一���可复制的 `droidspaces.config` defconfig 片段,类似于[此页面](./Kernel-Configuration.md#required-kernel-configuration),以确保你的内核与 Droidspaces 完全兼容。 +3. **内核配置**:如果你是一位内核开发者,你可以找到可复制的 `droidspaces.config` defconfig 片段,类似于[此页面](./Kernel-Configuration.md#required-kernel-configuration),以确保你的内核与 Droidspaces 完全兼容。 ## 下一步 From 4206f21f6b8f8d0e203591688afbf27fc39011bc Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sun, 28 Jun 2026 18:15:58 +0200 Subject: [PATCH 03/25] Added translation using Weblate (Tamil) (#221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added translation using Weblate (Tamil) Translated using Weblate (Chinese (Traditional Han script)) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (German) Currently translated at 97.6% (490 of 502 strings) Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/de/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hant/ Translation: Droidspaces/Strings Co-authored-by: Jung Chi Wang Co-authored-by: MonkiFantasy Co-authored-by: Sandmann79 Co-authored-by: தமிழ்நேரம் --- Android/app/src/main/res/values-de/strings.xml | 2 +- Android/app/src/main/res/values-ta/plurals.xml | 3 +++ Android/app/src/main/res/values-ta/strings.xml | 3 +++ Android/app/src/main/res/values-zh-rCN/strings.xml | 3 +++ Android/app/src/main/res/values-zh-rTW/strings.xml | 3 +++ 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Android/app/src/main/res/values-ta/plurals.xml create mode 100644 Android/app/src/main/res/values-ta/strings.xml diff --git a/Android/app/src/main/res/values-de/strings.xml b/Android/app/src/main/res/values-de/strings.xml index 7d39b3e0..207ba370 100644 --- a/Android/app/src/main/res/values-de/strings.xml +++ b/Android/app/src/main/res/values-de/strings.xml @@ -264,7 +264,7 @@ Kommuniziert direkt mit dem Host Linux-Kernel. Kein Hypervisor, keine Virtualisierungsschicht. Von Grund auf unkillbar Unterstützt die native Integration von init.rc und zweistufige Daemons im Userspace. Absolut unkillbar. - systemd / OpenRC mit PID 1 + systemd / OpenWrt procd / OpenRC mit PID 1 Vollständige Unterstützung des Init-Systems. Echte Dienstverwaltung, keine simulierte Umgebung. Vollständige Isolation Privater PID-Baum, Einhängepunkte, Hostname, IPC und cgroup-Hierarchie pro Container. diff --git a/Android/app/src/main/res/values-ta/plurals.xml b/Android/app/src/main/res/values-ta/plurals.xml new file mode 100644 index 00000000..55344e51 --- /dev/null +++ b/Android/app/src/main/res/values-ta/plurals.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Android/app/src/main/res/values-ta/strings.xml b/Android/app/src/main/res/values-ta/strings.xml new file mode 100644 index 00000000..55344e51 --- /dev/null +++ b/Android/app/src/main/res/values-ta/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Android/app/src/main/res/values-zh-rCN/strings.xml b/Android/app/src/main/res/values-zh-rCN/strings.xml index 0be64270..7cb5a704 100644 --- a/Android/app/src/main/res/values-zh-rCN/strings.xml +++ b/Android/app/src/main/res/values-zh-rCN/strings.xml @@ -499,4 +499,7 @@ 没有未知状态的服务 已检测到 OpenWrt/procd OpenWrt + 磁盘占用 + 已使用 %1$s / %2$s + 计算中… diff --git a/Android/app/src/main/res/values-zh-rTW/strings.xml b/Android/app/src/main/res/values-zh-rTW/strings.xml index a2f2d13e..1b29168a 100644 --- a/Android/app/src/main/res/values-zh-rTW/strings.xml +++ b/Android/app/src/main/res/values-zh-rTW/strings.xml @@ -494,4 +494,7 @@ 網關介面 eth1 主機網橋 + 磁碟使用情況 + %1$s / %2$s 已使用 + 正在計算… From ea1c703976becd300463d902bd3d6ef97223b11e Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Mon, 29 Jun 2026 08:50:32 +0200 Subject: [PATCH 04/25] Update translation files (#224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated by "Remove blank strings" add-on in Weblate. Update translation files Updated by "Remove blank strings" add-on in Weblate. Translated using Weblate (Tamil) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Tamil) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Tamil) Currently translated at 100.0% (3 of 3 strings) Translated using Weblate (Pangasinan (pag_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Pangasinan (pag_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Iloko (ilo_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Iloko (ilo_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Filipino) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Filipino) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Cebuano (ceb_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Cebuano (ceb_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (cbk_PH (generated) (cbk_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (cbk_PH (generated) (cbk_PH)) Currently translated at 45.6% (229 of 502 strings) Translated using Weblate (Portuguese) Currently translated at 49.4% (248 of 502 strings) Translated using Weblate (Portuguese) Currently translated at 49.4% (248 of 502 strings) Translated using Weblate (Chinese (Traditional Han script)) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Chinese (Traditional Han script)) Currently translated at 100.0% (502 of 502 strings) Translated using Weblate (Italian) Currently translated at 86.4% (434 of 502 strings) Translated using Weblate (Italian) Currently translated at 86.4% (434 of 502 strings) Translated using Weblate (Indonesian) Currently translated at 99.4% (499 of 502 strings) Translated using Weblate (Indonesian) Currently translated at 99.4% (499 of 502 strings) Translated using Weblate (Indonesian) Currently translated at 66.6% (2 of 3 strings) Translated using Weblate (Japanese) Currently translated at 82.2% (413 of 502 strings) Translated using Weblate (Japanese) Currently translated at 82.2% (413 of 502 strings) Translated using Weblate (Japanese) Currently translated at 66.6% (2 of 3 strings) Translated using Weblate (Sinhala) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Khmer (Central)) Currently translated at 89.8% (451 of 502 strings) Translated using Weblate (Khmer (Central)) Currently translated at 89.8% (451 of 502 strings) Translated using Weblate (Romanian) Currently translated at 72.9% (366 of 502 strings) Translated using Weblate (Romanian) Currently translated at 72.9% (366 of 502 strings) Translated using Weblate (Romanian) Currently translated at 66.6% (2 of 3 strings) Translated using Weblate (Sinhala) Currently translated at 62.7% (315 of 502 strings) Translated using Weblate (Sinhala) Currently translated at 62.7% (315 of 502 strings) Translated using Weblate (Turkish) Currently translated at 62.3% (313 of 502 strings) Translated using Weblate (Turkish) Currently translated at 62.3% (313 of 502 strings) Translated using Weblate (Turkish) Currently translated at 62.3% (313 of 502 strings) Translated using Weblate (Turkish) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Russian) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Hindi) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (French) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Spanish) Currently translated at 33.3% (1 of 3 strings) Translated using Weblate (Russian) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Russian) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Hindi) Currently translated at 46.8% (235 of 502 strings) Translated using Weblate (Hindi) Currently translated at 46.8% (235 of 502 strings) Translated using Weblate (French) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (French) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Spanish) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (Spanish) Currently translated at 45.0% (226 of 502 strings) Translated using Weblate (German) Currently translated at 97.6% (490 of 502 strings) Translated using Weblate (German) Currently translated at 97.6% (490 of 502 strings) Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/es/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/fr/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/hi/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/id/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ja/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ro/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ru/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/si/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/ta/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/plurals/tr/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/cbk_PH/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ceb_PH/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/de/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/es/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/fil/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/fr/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/hi/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/id/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ilo_PH/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/it/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ja/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/km/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/pag_PH/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/pt/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ro/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ru/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/si/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/ta/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/tr/ Translate-URL: https://hosted.weblate.org/projects/droidspaces/strings/zh_Hant/ Translation: Droidspaces/Plurals Translation: Droidspaces/Strings Co-authored-by: Ravindu Deshan Co-authored-by: Yusuf Co-authored-by: தமிழ்நேரம் --- .../app/src/main/res/values-ta/plurals.xml | 14 +- .../app/src/main/res/values-ta/strings.xml | 498 +++++++++++++++++- 2 files changed, 510 insertions(+), 2 deletions(-) diff --git a/Android/app/src/main/res/values-ta/plurals.xml b/Android/app/src/main/res/values-ta/plurals.xml index 55344e51..78e6aa09 100644 --- a/Android/app/src/main/res/values-ta/plurals.xml +++ b/Android/app/src/main/res/values-ta/plurals.xml @@ -1,3 +1,15 @@ - \ No newline at end of file + + %d உறுதி + %d உறுதியளிக்கிறது + + + %d அமர்வு இயங்குகிறது + %d அமர்வுகள் இயங்குகின்றன + + + %d கொள்கலன் + %d கொள்கலன்கள் + + diff --git a/Android/app/src/main/res/values-ta/strings.xml b/Android/app/src/main/res/values-ta/strings.xml index 55344e51..fc4b33ac 100644 --- a/Android/app/src/main/res/values-ta/strings.xml +++ b/Android/app/src/main/res/values-ta/strings.xml @@ -1,3 +1,499 @@ - \ No newline at end of file + ரூட் அணுகல் சோதனை + எந்த லினக்ச் திறன்களையும் (முழு ரூட் சக்தி) கைவிட வேண்டாம். + சேமிப்பக கட்டமைப்பு + நீங்கள் என்ன செய்கிறீர்கள் என்பது உங்களுக்குத் தெரியாவிட்டால் இதை மாற்ற வேண்டாம். தவறான init பைனரியை அமைப்பது, கொள்கலன் பூட் செய்வதைத் தடுக்கும். + %1$d மாறி(கள்) உள்ளமைக்கப்பட்டது + நிராகரி + ரூட் அணுகல் மறுக்கப்பட்டது + SELinux இசைவு + தெரியாத நிலையில் சேவைகள் இல்லை + தொகுதிக் கோப்புகளைப் பிரித்தெடுக்கிறது... + பதிவிறக்கத்தை மீண்டும் தொடங்க முடியாது + தார்பால் + ரேம் பயன்பாடு + விருப்பத்தேர்வு (எ.கா. 8080 அல்லது 1000-2000) + மூடு + ஆண்ட்ராய்டு க்கான LXC-பாணி கொள்கலன் மேலாளர் + OLED காட்சிகளுக்கான தூய கருப்பு பின்னணி + மதிப்பாய்வு கட்டமைப்பு + பராமரிப்பாளர் + மாற்றங்களைச் சேமிக்கவும் + \"%1$s\" ஐ ஒரு சிறிய படத்திற்கு மாற்றுவது ஒரு பிரத்யேக ext4 கோப்பு முறைமையை உருவாக்கும். இந்த செயல்பாடு குறுக்கிடப்பட்டால் அழிவுகரமானது. உங்கள் தரவை காப்புப் பிரதி எடுக்கவும். + மாறியைச் சேர்க்கவும் + Droidspacesக்கு புதியதா? + உள்ளமை பெயர்வெளி உருவாக்கத்தைத் தடுப்பதன் மூலம் மரபு கர்னல்களில் (எ.கா., 4.14.x) கர்னல்-நிலை VFS முட்டுக்கட்டைகளைத் தடுக்கிறது. \n\nஎச்சரிக்கை: இதை இயக்குவது கொள்கலனுக்குள் Docker, Podman, LXC மற்றும் Systemd சாண்ட்பாக்சிங் ஆதரவைத் தடுக்கும். + அகற்று + பின்தளம்: நடவடிக்கை தேவை + தெரியவில்லை + VirGL கூடுதல் கொடிகள் + பதிவுகளைப் பார்க்கவும் + இயல்புநிலைக்கு காலியாக விடவும் + இந்த ஐபி ஏற்கனவே \"%1$s\"க்கு ஒதுக்கப்பட்டுள்ளது + அசாதாரணமானது + பின்தளம்: நிறுவப்படவில்லை + கொள்கலன் தகவலைப் படிக்க முடியவில்லை + அரிதான படத்தைப் பயன்படுத்தவும் + முகவரி கண்டிப்பாக https:// உடன் தொடங்க வேண்டும் + நான் எந்த பிழைகளையும் புகாரளிக்க மாட்டேன் + VirGL 3D முடுக்கத்தை உள்ளமைக்கவும் + Force Cgroup V1 + ஆண்ட்ராய்டு 12+ Monet தீமிங்கைப் பயன்படுத்தவும் (மெட்டீரியல் யூ) + Init அமைப்பு + Termux:X11க்கு X11 சாக்கெட் மவுண்டிங்கை இயக்கு + கொள்கலனில் எழுத்துக்கள், எண்கள், ஐபன்கள் (-), அடிக்கோடுகள் (_), புள்ளிகள் (.) மற்றும் இடைவெளிகள் மட்டுமே இருக்க வேண்டும் + பின்தளம்: நிறுவப்பட்டது + முழு வன்பொருள்/சிபியு அணுகல் + கொள்கலனை நாடாகாப்பகபந்து ஆக ஏற்றுமதி செய்யவும் + லினக்ச் கொள்கலன்கள். பழமை. மேல்நிலை இல்லை. + சேமிப்பு + ச்பார்ச் படத்திற்கு நகர்த்தவும் + சிபியு பயன்பாடு + டிராய்ச்பேச்களை தொடர்ந்து ஆய்வு செய்ய ரூட் அணுகலை வழங்கவும்! + தனிப்பட்ட PID மரம், மவுண்ட் டேபிள், ஓச்ட்பெயர், IPC மற்றும் ஒரு கொள்கலனுக்கு cgroup படிநிலை. + எ.கா. --மல்டி-கிளையண்ட்ச் --ஆங்கிள்-வல்கன் + துறைமுகம் ஒரு எண்ணாக இருக்க வேண்டும் + உண்மையான லினக்ச் கொள்கலன்கள் + ஒரு ச்பேர்ச் படமானது ஒரு பிரத்யேக ext4 கோப்பு முறைமை படக் கோப்பை உருவாக்குகிறது, அது ஒரு லூப் சாதனமாக ஏற்றப்பட்டு, சிறந்த தனிமைப்படுத்தல் மற்றும் இணக்கத்தன்மையை வழங்குகிறது. + பைனரியை நிறுவுகிறது: %1$s + போதிய சேமிப்பு இல்லை + SELinux அனுமதியை அமைக்கவும் + தொடங்குங்கள் + முனையத்தைத் திறக்கவும் + Droidspaces க்கான தேவைகள் + /proc மற்றும் /sys க்கு எழுதும் அணுகலை அனுமதிக்க சிறை முகமூடிகளை முடக்கவும். குறிப்பு: வன்பொருள் அணுகலும் இயக்கப்பட்டாலன்றி, /sys படிக்க மட்டுமே இருக்கும். + பிணையம் பிழை + HW + Droidspaces v6.1.0 இலிருந்து தொடங்கி, udevd ஆனது USB, block, input, TTY மற்றும் பிணைய துணை அமைப்புகளுக்கான உண்மையான அணுகலைக் கொண்டுள்ளது. உங்கள் கன்டெய்னர் ஆண்ட்ராய்டு தற்போது பயன்படுத்தும் வன்பொருளை சொந்தமாக வைத்திருக்க முடியும். \n\nஉங்கள் விசைப்பலகை, SD அட்டை அல்லது USB சாதனம் ஒரு கண்டெய்னரை அறிமுகப்படுத்திய பிறகு ஆண்ட்ராய்டு இல் வேலை செய்வதை நிறுத்தினால் - அது ஒரு பிழை அல்ல. கொள்கலன் அதை எடுத்தது. முழு வன்பொருள் அணுகலைக் கேட்டுள்ளீர்கள். \n\nஇந்த பயன்முறையைப் பயன்படுத்தும் போது வன்பொருள் முரண்பாடுகள் அல்லது கர்னல் பீதியால் ஏற்படும் சிக்கல்களைப் புகாரளிக்க வேண்டாம். + அனைத்து சலுகை பெற்ற கொடிகளையும் ஒரே நேரத்தில் இயக்கவும். + அரிதான படத்தின் அளவை மாற்றவும் + முகமூடி + புரவலன் வன்பொருளை (GPU, சென்சார்கள், USB, பிளாக் சாதனங்கள்) நேரடியாக உங்கள் கொள்கலன்களுக்கு வெளிப்படுத்துங்கள். + பைண்ட் மவுண்ட்டைச் சேர்க்கவும் + டீமான் பயன்முறை + Seccomp syscall வடிகட்டலை முடக்கவும். இது, உள்ளமை சாண்ட்பாக்சிங்கிற்கு (Bubblewrap, Flatpak) கண்டிப்பாகத் தேவைப்படும் சலுகையற்ற பயனர் பெயர்வெளிகள் போன்ற மேம்பட்ட கர்னல் அம்சங்களை செயல்படுத்துகிறது மற்றும் மரத்திற்கு வெளியே உள்ள கர்னல் தொகுதிகளை ஏற்றவும் அனுமதிக்கிறது. + கர்னல் + கோப்பு ஏற்கனவே உள்ளது + %1$s %2$s இல் தோல்வியடைந்தது + கொள்கலன் செய்தி + கொள்கலனைத் திருத்து: %1$s + ஆபத்தான பிரதேசம் + நுழைவாயில் உள்ள இடைமுகம் + ஆண்ட்ராய்டு ஓச்டில் உருவாக்கப்பட்ட மெய்நிகர் சுவிட்சின் பெயர். LAN பெயரிலிருந்து (ds-<lan>) தானாகப் பெயரிட காலியாக விடவும். உங்களுக்கு சரியான பாலத்தின் பெயர் தேவைப்பட்டால் மட்டுமே இதை அமைக்கவும். அதிகபட்சம் 15 எழுத்துகள். + Systemd/OpenWrt/OpenRC கிடைக்கவில்லை + பயனரைத் தேர்ந்தெடுக்கவும் + கொள்கலன் அமைப்பு + சேவையை மீண்டும் ஏற்றவும் + கொள்கலனை நிறுவல் நீக்கவும் + உள்ளக பயனர்கள் இல்லை + எ.கா. /mnt/sdcard + Droidspaces ஐ நிறுவுதல் + சேமிக்கப்பட்டது + பிழை அறிக்கை + கொள்கலன்கள் நிறுவப்படவில்லை + கொள்கலனை உள்ளிட பயனரைத் தேர்ந்தெடுக்கவும்: + நுழைவாயில் கொள்கலனைத் தேர்ந்தெடுக்கவும் + systemd / OpenWrt procd / OpenRC என PID 1 + ஐபி முகவரி + \"Droidspaces உருவாக்குபவர்கள்\" கீழ் Rootfs tarballs திறந்த மூல மற்றும் வெளிப்படையானவை. இந்தக் கார்டைத் தட்டுவதன் மூலம் எங்கள் மாற்றங்களை நீங்கள் கைமுறையாகப் பதிவிறக்கலாம் அல்லது ஆய்வு செய்யலாம். + இந்த கொள்கலனில் IPv6 ஐ முடக்கவும். IPv6 ஐ முடக்குவது ஓச்டில் இயங்கும் VPN பயன்பாடுகளை உடைக்கக்கூடும். + ஒரு கொள்கலன் அதன் சொந்த நுழைவாயிலாக இருக்க முடியாது + விருப்ப துவக்கம் + மீண்டும் முயற்சிக்கவும் + கணினி கருப்பொருள் தானாக பொருந்தும் + பற்றி + IPv6 ஐ முடக்கு + GKI கர்னல் தேவைகள் (>=5.4) + (சமச்சீர்) + 172.28.x.x சப்நெட்டில் இந்தக் கொள்கலனுக்கான நிலையான IPv4 ஐ அமைக்கவும். முதல் துவக்கத்தில் தானாக ஒதுக்க அதை காலியாக விடவும். + லேன் பெயர் + உள்ளமைக்கப்பட்ட மெய்நிகராக்கம் அல்லது மேம்பட்ட வன்பொருள் அணுகலுக்கான சிறுமணி பாதுகாப்பு தளர்வை உள்ளமைக்கவும். + GPU முனைகளை தனிமைப்படுத்தப்பட்ட / dev இல் பிரதிபலிக்கவும் (முழு வன்பொருள் பாச்த்ரூ இல்லை) + முழு சலுகை பெற்ற கொள்கலன்கள் + தெளிவு + eth1 + Droidspaces rootfs பதிவிறக்கம் + தெரியவில்லை + தொடக்கம் முடிவை விட குறைவாக இருக்க வேண்டும் + துறைமுகங்கள் எண்களாக இருக்க வேண்டும் + ரன்-அட்-பூட் கொள்கலன்கள் தொடங்கும் வரிசை + மறுதொடக்கத்திற்குப் பிறகு மாற்றங்கள் நடைமுறைக்கு வரும் + பின்தளம் கிடைக்கவில்லை + இயக்கப்பட்ட சேவைகள் இல்லை + உள்நுழைவை நகலெடுக்கவும் + நிறுவல் பாதை + %1$s பயனருக்கு உள்நுழைவு கட்டளை நகலெடுக்கப்பட்டது + தொகுதியை நிறுவுதல் + இடைமுகம் ஏற்கனவே மற்றொரு பிரிவால் பயன்படுத்தப்பட்டது (\'%1$s\'). வேறு ஒன்றைப் பயன்படுத்தவும். + பின்பக்கம்: சரிபார்க்கிறது... + கொள்கலன்கள் + மறைகுறியாக்கப்பட்ட சேமிப்பகம், F2FS /தரவு பகிர்வுகள் அல்லது நேரடி அடைவு மவுண்டிங்கில் பொருந்தக்கூடிய சிக்கல்களைக் கொண்ட பிற கோப்பு முறைமைகளில் கண்டெய்னர்களைப் பயன்படுத்தும் போது அரிதான படங்கள் பரிந்துரைக்கப்படுகின்றன. + களஞ்சியத்தின் பெயர் + பைனரி நிறுவல் தோல்வியடைந்தது + கணினி உள்ளமைவை சரிசெய்ய தட்டவும் + %1$s / %2$s பயன்படுத்தப்பட்டது + தேவைகள் சரிபார்ப்பு வெற்றிகரமாக முடிந்தது + நிறுவலைச் சரிபார்க்கிறது... + முழு வன்பொருள் அணுகல் + புதுப்பிப்பு + முழு init கணினி உதவி. உண்மையான பணி மேலாண்மை, உருவகப்படுத்தப்பட்ட சூழல் அல்ல. + அறிவிலிமையம் + %1$d sessions running · tap பெறுநர் restore + முடக்கப்பட்டது + மேசிச்க் தொகுதி வெற்றிகரமாக நிறுவப்பட்டது + இடம்பெயர்வு செயல்பாட்டைத் தொடங்குகிறது... + வெடிமையுடைய + எந்த கொள்கலன்களும் ரன் அட் பூட்டில் இயக்கப்படவில்லை. + நுழைவாயில் கொள்கலன் + கர்னல் தேவைகள் + மீட்டமை + இந்த LAN பிரிவுக்கான சிட்டை. ஒரே கேட்வே மற்றும் லேன் பெயரைப் பகிர்ந்து கொள்ளும் கன்டெய்னர்கள் ஒரே மெய்நிகர் சுவிட்சில் இணைகின்றன, மேலும் ஒன்றையொன்று பார்க்க முடியும். தனிமைப்படுத்தப்பட்ட இரண்டாவது பிரிவைச் சுழற்ற வேறு பெயரைப் பயன்படுத்தவும். இயல்புநிலை: lan. + நகலெடு + அடைவு + இந்த விருப்பங்களை இயக்குவதன் மூலம், உங்கள் சாதனத்தின் பாதுகாப்பை நீங்கள் வேறுபாடின்மை செய்கிறீர்கள். தரவு இழப்பு, ப்ரிக் செய்யப்பட்ட சாதனங்கள் அல்லது வித்தியாசமான பிழைகளுக்கு நாங்கள் பொறுப்பல்ல. இந்த முறைகளைப் பயன்படுத்தும் போது ஏற்பட்ட சிக்கல்களைப் புகாரளிக்க வேண்டாம். + சரக்குப் பெட்டகம் + Cgroup V1 + கோப்பு கிடைக்கவில்லை (404) + கொள்கலனை நிறுவவும் + கீழே உள்ள பொத்தானைப் பயன்படுத்தி கொள்கலனை நிறுவவும் + இயக்கப்பட்டது + TCP + கிடைக்கும் பயனர்கள் + ரூட் அணுகல் வழங்கப்பட்டது + துறைமுகம் பகிர்தல் + கண்டறியப்பட்ட கட்டமைப்பு: %1$s + OpenRC சேவைகள் + விர்சிஎல் + பின்தளத்தில் புதுப்பிப்பு உள்ளது, புதுப்பிக்க இங்கே சொடுக்கு செய்யவும் + இசைவு வழங்கவும் + தொகுதியை நிறுவுகிறது... + SELinux விதிகளைப் பயன்படுத்த மறுதொடக்கம் பரிந்துரைக்கப்படுகிறது மற்றும் துவக்கத்தில் டீமானைத் தொடங்கவும். + புரவலன் பாலம் + ரேம்: + %1$s களஞ்சியத்தில் இல்லை + பல்ச் ஆடியோவை உள்ளமைக்கவும் + இந்த கொள்கலனில் systemd, OpenWrt/procd அல்லது OpenRC நிறுவப்படவில்லை + ஆக்டெட் %1$d + LXC, Podman மற்றும் Docker போன்ற அதே கர்னல் பெயர்வெளி தொழில்நுட்பம். எமுலேசன் இல்லை, க்ரூட் இல்லை. + Droidspaces பின்தளம் வெற்றிகரமாக நிறுவப்பட்டது + பிணையம் பயன்முறை + தேவைகளை சரிபார்க்கவும் + மூலக் குறியீடு + Droidspaces ஆனது உங்கள் முனைய அமர்வுகளை பின்னணியில் இயங்க வைப்பதற்கு ஒரு நிலையான அறிவிப்பைக் காட்ட வேண்டும். இது இல்லாமல், ஆண்ட்ராய்டு (குறிப்பாக சாம்சங் சாதனங்களில்) எதிர்பாராத விதமாக டெர்மினல் சேவையை அழிக்கக்கூடும். + கொள்கலனை நிறுவல் நீக்கவா? + மறுதொடக்கம் + தவறான எண் + முழுமையான பாதையை வடிகட்டவும் அல்லது தட்டச்சு செய்யவும்… + எழுத்துக்கள், இலக்கங்கள், _ அல்லது - ஆகியவற்றை மட்டும் பயன்படுத்தவும் + விருந்தோம்பி + நீங்கள் இப்போது Droidspaces ஐப் பயன்படுத்தலாம் + HTTP தரவு பிழை + இது \"%1$s\" கண்டெய்னரையும் அதன் எல்லா தரவையும் நிரந்தரமாக நீக்கும். இந்தச் செயலைச் செயல்தவிர்க்க முடியாது. \n\nகொள்கலன் இயங்கினால், அது முதலில் நிறுத்தப்படும். + இந்த இணைப்பின் இடைமுகப் பெயர் கேட்வே கொள்கலனின் உள்ளே (எ.கா. OpenWRT இல் eth1) எனக் காட்டுகிறது. இது DHCP இல் பணி செய்ய உங்கள் நுழைவாயில் அமைக்கப்பட்ட இடைமுகத்துடன் பொருந்த வேண்டும். ஒரே நுழைவாயிலில் உள்ள ஒவ்வொரு தனிப் பிரிவுக்கும் அதன் சொந்தப் பெயர் தேவை. இயல்புநிலை: eth1. + களஞ்சியத்தை ஏற்ற முடியவில்லை + புரவலன்பெயர் + நிறுவல் நீக்குகிறது... + வன்பொருள் அணுகல் + சேமிப்பிடம் கிடைக்கவில்லை + பின் + அதை இங்கே பார்க்க முதலில் ஒரு கொள்கலனைத் தொடங்கவும் + Magisk/APatch, GrapheneOS, போன்றவற்றிலிருந்து seccomp பிளாக்சைத் தவிர்க்க, Droidspaces ஒரு நிலையான கணினி-நிலை டீமானாக இயக்கவும். இது பயனர் இடத்திலிருந்து கட்டளைகளைப் பெற்று இயக்குவதன் மூலம் உயர்-சலுகை செயல்பாடுகளை செயல்படுத்துகிறது (மறுதொடக்கம் தேவை). + மறுவரிசைப்படுத்த இழுக்கவும் + கணக்கிடுகிறது… + கேட்வேயின் மெய்நிகர் LAN இல் இந்தக் கொள்கலன் எவ்வாறு செருகப்படுகிறது என்பதை இவை கட்டுப்படுத்துகின்றன. இயல்புநிலைகள் ஒரு நுழைவாயிலுக்குப் பின்னால் ஒரு லேனுக்கு வேலை செய்கின்றன - பல லேன் பிரிவுகள் அல்லது ஒன்றுக்கு மேற்பட்ட கேட்வேகளை இயக்கும் போது மட்டுமே அவற்றை மாற்றவும். + நுழைவாயிலை உள்ளமைக்கவும் + OpenWrt/procd கண்டறியப்பட்டது + தொடங்கு + அதிகபட்ச அளவு 512 சிபி + கொள்கலன் பெயர் * + தோற்றம் + ரூட் அணுகலை சரிபார்க்க கீழே சொடுக்கு செய்யவும் + ஓச்ட்பெயரில் எழுத்துக்கள், எண்கள் மற்றும் கோடுகள் மட்டுமே இருக்க வேண்டும் (-) + துறைமுகங்கள் 1-65535 ஆக இருக்க வேண்டும் + இயக்க நேரம் + ஓச்டுக்கு MS_SHARED மவுண்ட் பிரசாரத்தை இயக்கவும். + பதிப்பு + நிறுவவும் + எனக்கு புரிகிறது + அரிதான படத்திற்கு நகர்த்தவும் + படிக்க மட்டும் + ரேம் மட்டும் பயன்முறை (நிறுத்தத்திற்குப் பிறகு மாற்றங்கள் மறைந்துவிடும்) + சாதன வடிகட்டலைத் தவிர்க்கவும். அனைத்து புரவலன் /டெவ் முனைகளும் தெரியும். + சரி + நுழைவாயிலை உள்ளமைக்கவும் + அறுவை மருத்தீடு வெற்றிகரமாக முடிந்தது! + நிறுத்தப்பட்டது + பைனரிகள் மற்றும் துவக்க தொகுதியை மீண்டும் நிறுவவும் + டெட்லாக் சீல்ட் + GPU + ச்பார்ச் படத்தின் அளவை மாற்றவும் + நிறுத்து + துவக்கத்தில் இயக்கவும் + அனுமதிகளை அமைக்கிறது... + 4-512 + நெட்வொர்க்கிங் + கொள்கலன் இயங்குகிறது + DNS சேவையகங்கள் + %1$dGB + பின்தளம் + PID: %1$d + தானியங்கு துவக்க முன்னுரிமை + மேம்பட்ட பயனர்களுக்கு சலுகை பெற்ற பயன்முறையுடன் பாதுகாப்பு தடைகளைத் தளர்த்தவும். + ஆதரிக்கப்படும் ஏபிஐக்கள் + அரிதான படங்கள் பற்றி + அடுத்து: கட்டமைப்பு + பாலம் ஏற்கனவே \'%1$s\' ஆல் பயன்படுத்தப்பட்டது. வேறு LAN பெயரைப் பயன்படுத்தவும். + ஆவியாகும் முறை + அளவு (சிபி) + %1$s கண்டெய்னரை நிறுத்த முடியவில்லை + கிடைக்கவில்லை + நிறுவல் நீக்கவும் + கோப்பகங்களை உருவாக்குகிறது... + சிறப்புரிமை பெற்றது + விருப்பங்கள்: %1$s + ds-lan + கர்னல் தேவைகள் இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டது + கோப்பு முறைமை பிழை + முகமூடி சேவைகள் இல்லை + தவிர் + தேவைகள் சரிபார்ப்பு பிழைகளுடன் முடிந்தது + களஞ்சியம் + நிறுவல் தயாராகிறது... + உள்ளமைவு + தொகுதி நிறுவலைத் தயாராகிறது... + வெளியீடு இல்லை + ரூட் அணுகலைச் சரிபார்க்கவும் + கொள்கலன் பாதை: %1$s + நிறுவல் தோல்வியடைந்தது + NAT (இயல்புநிலை) + களஞ்சியங்களை நிர்வகிக்கவும் + அறியப்படாத பிழை ஏற்பட்டது + பதிவுகள்: %1$s + திரை பூட்டப்பட்டிருந்தாலும், தரவு குறியாக்கம் செய்யப்பட்டிருந்தாலும், பூட்டில் கொள்கலன்களைத் தானாகத் தொடங்கவும். + இந்த கொள்கலனை திசைவியாக செயல்படும் மற்றொரு கொள்கலன் வழியாக இயக்கவும் (எ.கா. OpenWRT). அந்த நுழைவாயில் முதலில் இயங்க வேண்டும். + சுற்றுச்சூழல் மாறிகள் + எதிர்பாராத HTTP பதில் + வேக் லாக்: ஆஃப் + வெற்று அடைவு + நிலையான சேவைகள் இல்லை + பதிவுகளை அழிக்கவும் + பங்களிப்பாளர்கள் + இருண்ட கருப்பொருள் இயக்கவும் + ஆபரேசன் தோல்வி! + விருந்தோம்பி + நெறிமுறை + தனிப்பயன் களஞ்சியங்கள் எதுவும் இதுவரை குழுசேரவில்லை. + துறைமுகம் முன்னோக்கி சேர்க்கவும் + இயல்புநிலை init (/sbin/init) பயன்படுத்த காலியாக விடவும் + மறுதொடக்கம் + விருப்பங்கள் + தேடல் சேவைகள்... + ரூட் அணுகல் இல்லை + OpenRC + இந்தப் பெயரில் ஒரு கொள்கலன் ஏற்கனவே உள்ளது + எதுவும் இல்லை (காற்று இடைவெளி) + செயலில் உள்ள கொள்கலன் முனைய அமர்வுகள் + Termux:X11 கூடுதல் கொடிகள் + முடக்கு + கேட்வே (மெய்நிகர் திசைவி) + ஒவ்வொரு வரிசையும் ஒரு KEY=VALUE இணை + வேக் லாக்: ஆன் + ஏற்றுமதியைத் தொடங்குகிறது... + கணினியின் இயல்புநிலை வண்ணத் தட்டுகளைப் பயன்படுத்தவும் + /sbin/init (இயல்புநிலை) + கொள்கலன் பாதையை உள்ளிடவும் + ரூட் அணுகல் இல்லாததால் இந்தப் பக்கம் முடக்கப்பட்டுள்ளது + குழுசேர் + பரவல் + பெயர் காலியாக இருக்கக்கூடாது + கொள்கலன் விருப்பங்கள் + கோப்புறையைத் தேர்ந்தெடு + பின்தளத்தை மீண்டும் நிறுவவும் + %1$sing கண்டெய்னரில் %2$s தோல்வி + டெர்மினல் பதிவுகள் + முழுமையான தனிமைப்படுத்தல் + ரூட்ஃப்ச் களஞ்சியம் + மேனுவல் டெட்லாக் சீல்டு + சலுகை பெற்ற பயன்முறை + பல வழிமாற்றுகள் + எ.கா. 1.1.1.1,8.8.8.8 (விரும்பினால்) + UDP + Droidspaces பின்தளம் நிறுவப்படவில்லை அல்லது சிதைக்கப்படவில்லை. முதலில் அதை நிறுவவும். + ஓடுகிறது + %1$s: %2$s + இயக்கு + %1$.1f%% + டெர்மினல் அமர்வுகள் + பழைய தொகுதியை நீக்குகிறது... + மரபு Cgroup V1 படிநிலையின் கட்டாயப் பயன்பாடு + ஆண்ட்ராய்டு பதிப்பு + %1$s கண்டெய்னரை நிறுவல் நீக்குவதில் தோல்வி + தவறான வரம்பு வடிவம் (START-END) + கொள்கலன் துறைமுகம் (1-65535 அல்லது வரம்பு) + முனையத்தில் + கணினி பாதையில் Droidspaces ஐ ஒருங்கிணைக்கவும் + ஆபரேசன் தோல்வியடைந்தது + தனிப்பயன் rootfs.json ஊட்டங்களுக்கு குழுசேரவும். + VirGL வழியாக 3D வன்பொருள் முடுக்கத்தை இயக்கவும் + இருண்ட கருப்பொருள் + ரத்துசெய் + முகமூடியை அவிழ்த்து விடுங்கள் + முக்கிய + SELinux இசைவு + IPv6 ஐ முடக்கு + அடுத்து: சேமிப்பு + GKI அல்லாத கர்னல் தேவைகள் (<=4.19) + சேவைகளைப் பெறுகிறது... + எ.கா. -dpi 160 -force-sysvshm + பதிவுகளை நகலெடுக்கவும் + புதுப்பிப்பு + திற + பிழைக் குறியீடு %1$d + NAT + தயவுசெய்து .tar.xz அல்லது .tar.gz கோப்பைத் தேர்ந்தெடுக்கவும். கோப்பு வகையைத் தீர்மானிக்க முடியவில்லை. + எதுவுமில்லை + பாதுகாப்பு & துவக்கம் + நுழைவாயில் அமைப்புகள் + ஏற்கனவே உள்ள துறைமுகம் முன்னோக்கி விதியுடன் மேலெழுகிறது + உங்கள் கோரிக்கையை நாங்கள் செயல்படுத்தும் வரை காத்திருக்கவும்... + குழு + %1$d MB (%2$.1f%%) + கொள்கலன் %1$s வெற்றிகரமாக நிறுவல் நீக்கப்பட்டது + SELinux நிலை + X11 + நுழைவாயிலாக செயல்பட மற்றொரு கொள்கலனை நிறுவவும் + புரவலன் லினக்ச் கர்னலுடன் நேரடியாகப் பேசுகிறது. ஐப்பர்வைசர் இல்லை, மெய்நிகர் இயந்திர அடுக்கு இல்லை. + தயவுசெய்து .tar.xz அல்லது .tar.gz கோப்பைத் தேர்ந்தெடுக்கவும். தேர்ந்தெடுக்கப்பட்டது: %1$s + AMOLED பயன்முறை + முனையத்தில் + rootfs.json முகவரி + சுழியம் மேல்நிலை + அனைத்து + பதிவிறக்கம் + பதிவிறக்கம் + மொழி + நிறுவல் பதிவுகள் + புரவலன் பாதை: %1$s + Systemd + தேடல் + புரவலன் துறைமுகம் (1-65535 அல்லது வரம்பு 100-200) + பின்பக்கம்: சிதைந்துள்ளது + Termux:X11ஐ உள்ளமைக்கவும் + நேட்டிவ் init.rc ஒருங்கிணைப்பு மற்றும் 2-லேயர் யூசர்ச்பேச் டெமான்களை ஆதரிக்கிறது. முற்றிலும் அழிக்க முடியாதது. + பின்தளம்: புதுப்பிப்பு உள்ளது + CPU: + கட்டிடக்கலை + அனுமதிகளை வழங்குகிறது... + Termux தேவைகள் + படத்தின் அளவு + பல்ச் ஆடியோ + கணினி கருப்பொருள் பின்பற்றவும் + நிர்வகிக்கவும் + துவக்கத்தில் கொள்கலனைத் தொடங்கவும் + வழிகாட்டி + பிழைத்திருத்தத்திற்கான கணினி செய்தி மற்றும் பதிவுகளை சேகரிக்கவும் + கொள்கலன்கள் இயங்கவில்லை + தேவைகள் சரிபார்ப்பு + ரத்துசெய் + GPU அணுகல் + கொள்கலன்களை நிர்வகிக்க ரூட் அணுகல் தேவை. + மறுவரிசைப்படுத்த இழுக்கவும். கொள்கலன்கள் மேலிருந்து கீழாகத் தொடங்குகின்றன - முதலில் ஒரு நுழைவாயிலை (எ.கா. OpenWRT) வைக்கவும், அதனால் அதன் வழியாக செல்லும் கொள்கலன்களுக்கு முன் அது பூட் ஆகும். + அசாதாரண சேவைகள் இல்லை + முடக்கப்பட்ட சேவைகள் இல்லை + உறுதிப்படுத்த, \"எந்த பிழைகளையும் நான் புகாரளிக்க மாட்டேன்\" என்று பெரிய எழுத்துக்களில் தட்டச்சு செய்க: + கொள்கலன் உள்ளமைவைத் திருத்து + வீடு + %1$sக்கான பணி நிர்வாகம் அடுத்த பேட்சில் சேர்க்கப்படும். + டெலிகிராம் சேனல் + \"%1$s\"க்கான ச்பேச் படத்தின் அளவை மாற்றுகிறது. சுருங்குவதை விட அளவை அதிகரிப்பது பாதுகாப்பானது. உங்கள் தரவை காப்புப் பிரதி எடுக்கவும். + இயங்கும் சேவைகள் இல்லை + அண்மைக் கால வெளியீட்டில் ரூட்ஃப்ச் டார்பால்கள் எதுவும் இல்லை + சரிபார்க்கிறது + நிலையான ஐபி முகவரி + குறைந்தபட்ச அளவு 4 சிபி + நுழைவாயில் + ஓடுகிறது + பிழை அறிக்கையை உருவாக்கவும் + %1$s %2$s செய் + ஒருங்கிணைப்பு & வன்பொருள் + சேமிக்கிறது... + லான் + ஓச்ட்/கன்டெய்னர் வரம்பு அகலம் பொருந்தவில்லை + பொருத்தங்கள் இல்லை + நிறுவல் முடிந்தது + OpenWrt + நிலையான + முகவரி காலியாக இருக்கக்கூடாது + அமைப்புகள் + கொள்கலனை நிறுத்துகிறது... + 1 அமர்வு இயங்குகிறது · மீட்டமைக்க தட்டவும் + ஏற்றுகிறது... + 4 முதல் 512 சிபி வரை அளவை உள்ளிடவும் + அறிவிப்பு இசைவு + எடுத்துக்காட்டுகள்: 8080 (ஒற்றை), 8000-8010 (வரம்பு). சமச்சீர் மேப்பிங்கிற்கு இலக்கை காலியாக விடவும். + NAT அமைப்புகள் + ஆயத்தம் + மிக நீளமானது - அதிகபட்சம் 15 எழுத்துகள் + %1$s கண்டெய்னரை ஏற்றுமதி செய்ய முடியவில்லை + ஒரு சிறிய படக் கோப்பில் கொள்கலனை உருவாக்கவும் + வெளியேறு + காலியாக இருந்தால், கொள்கலன் பெயரை ஓச்ட்பெயராகப் பயன்படுத்தும் + கட்டமைக்கப்படவில்லை + உள்ளமைவைப் புதுப்பிக்க முடியவில்லை + Droidspaces பற்றி + வட்டு பயன்பாடு + கொள்கலனை நிறுவுதல் + தனிப்பயன் களஞ்சியத்தைச் சேர்க்கவும் + வரம்பு: 1-254 + பவர் அப் ஆன் ஆட்டோ பூட் + தொடரவும் + ஆண்ட்ராய்டு சேமிப்பகத்தை ஏற்றவும் + ச்பேர்ச் பட கட்டமைப்பு + நிறுவவும் + 8 + பெயர் மிக நீளமானது - அதிகபட்சம் 17 எழுத்துகள் (கர்னல் லூப் சாதன பாதை வரம்பு) + %1$s: %2$s + அளவை மாற்றும் செயல்பாட்டைத் தொடங்குகிறது... + டெவலப்பர்(கள்) + ஆண்ட்ராய்டு சேமிப்பிடம் + , + கூடுதல் விருப்பங்கள் எதுவும் இயக்கப்படவில்லை + சேவைகள் எதுவும் இல்லை + தோல்வியடைந்தது + எண்கள், புள்ளிகள் மற்றும் பெருங்குடல்கள் மட்டுமே + கூட்டு + தொகுதி நிறுவல் தோல்வியடைந்தது + Systemd சேவைகள் + OpenWrt சேவைகள் + தேவைகள் + பாதை முழுமையானதாக இருக்க வேண்டும் (/ உடன் தொடங்கவும்) + ஓச்ட்பெயர்: %1$s + ரூட் அணுகல் இல்லை. + ஆண்ட்ராய்டு ரூட் செல்லில் droidspaces கட்டளையை அணுக /system/bin இல் ஒரு சிம்லிங்கை உருவாக்கவும். எச்சரிக்கை: உங்கள் மவுண்ட் சிச்டம் ஓவர்லேஃப்ச் மேவு மாட்யூல்களாக இருந்தால், இதை இயக்குவது பூட்லூப்பை ஏற்படுத்துகிறது. மேசிக் மவுண்ட் அடிப்படையிலான மவுண்ட் சிச்டத்தைப் பயன்படுத்தும் போது மட்டுமே இந்த விருப்பத்தைப் பயன்படுத்தவும் (மறுதொடக்கம் தேவை) + தனிப்பயன் தொடக்க பைனரி + நிறுவல் சுருக்கம் + ரூட் அணுகலைச் சரிபார்க்கிறது... + பயனர்களைப் புதுப்பிக்கவும் + வடிவமைப்பால் அழிக்க முடியாதது + முகமூடி பணி + சமச்சீர் மேப்பிங்கிற்கு காலியாக விடவும் + அறியப்படாத பிழை + மதிப்பு + இடைநிலைப்பலகைக்கு பதிவுகள் நகலெடுக்கப்பட்டன + அளவு தேவை + கொள்கலனின் பெயர் காலியாக இருக்கக்கூடாது + NAT மற்றும் எதுவுமில்லை பிணையம் முறைகளில் IPv6 எப்போதும் முடக்கப்பட்டிருக்கும். + பைண்ட் மவுண்ட்ச் + PulseAudio வழியாக ஆடியோ ஆதரவை இயக்கவும் + பிழை: %1$s + இந்த கொள்கலனுக்குள் ஒரு ஊடாடும் செல்லைத் திறக்கவும் + மேம்பட்ட விருப்பங்கள் + Droidspaces டெர்மினல் + கணினி இயல்புநிலை + சேவையை மீண்டும் தொடங்கவும் + இந்த நுழைவாயில் கொள்கலன் நிறுவப்படவில்லை + கொள்கலன் செய்தி + உங்கள் முதல் லினக்ச் கொள்கலனை எவ்வாறு அமைப்பது என்பதை அறிய இங்கே தட்டவும்! + முடிந்தது + From 901502daeaa2ca220c4f1d1d81ff62ac1ec823de Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Mon, 29 Jun 2026 12:57:24 +0530 Subject: [PATCH 05/25] net: self-heal delegated-LAN clients when the gateway (re)boots A delegated-LAN (gateway-mode) client loses its router whenever its gateway container reboots: the gateway's netns dies and takes the gateway-side veth with it, so the client's app veth survives on the bridge but the segment has no router. Clients also could not be wired at all until their gateway happened to be up. Make the gateway own the wiring, end to end: - gateway_wire_client() does the whole client wiring from the host side - bridge + gateway uplink, the app veth, a stable MAC, and the in-netns eth0 rename/up - so it behaves identically whether the client is just starting or already running. The gateway-mode child only brings up lo. - On every boot cycle the gateway container's monitor calls ds_net_rewire_gateway_clients(), which scans the running containers and runs gateway_wire_client() for each one that delegates to it. That re-establishes the gateway-side cable and every client's eth0 in the gateway's current netns, with no client restart. - A client started while its gateway is down now wires nothing and defers entirely to the gateway. This also closes a race: the client can no longer bake in gateway/LAN settings that the user edits before the gateway starts - the gateway wires each client from its current config. Supporting fixes: - Drop NLM_F_ACK on RTM_GETLINK: a successful GETLINK already replies with RTM_NEWLINK, so the extra ACK left a stray datagram in the socket buffer that desynced the next request's reply (ds_nl_link_exists false positives). Keep reading until our sequence matches. - Give gateway clients distinct veth prefixes (ds-c/ds-q) so the NAT last-container refcount cannot miscount them as live NAT containers. - Pin a stable, segment-derived MAC on the gateway-side cable and move+rename it into the gateway atomically, so OpenWrt's netifd sees one persistent eth1 instead of a churning random-MAC device. Signed-off-by: ravindu644 --- Documentation/Networking-From-Zero.md | 30 +- src/boot.c | 2 + src/include/droidspace.h | 6 + src/monitor.c | 15 +- src/net/netlink.c | 57 ++- src/net/network.c | 608 +++++++++++++++++++------- 6 files changed, 544 insertions(+), 174 deletions(-) diff --git a/Documentation/Networking-From-Zero.md b/Documentation/Networking-From-Zero.md index 3c13e273..9e005ae3 100644 --- a/Documentation/Networking-From-Zero.md +++ b/Documentation/Networking-From-Zero.md @@ -365,7 +365,7 @@ Android host kernel +-- ds-lan (host bridge - NO IP address, just a switch) | | | +-- ds-g[hash] (veth host-side, connected to OpenWRT's netns as eth1) -| +-- ds-v[pid] (veth host-side, connected to Kali's netns as eth0) +| +-- ds-c[pid] (veth host-side, connected to Kali's netns as eth0) | +-- [Kali container - net=gateway mode] netns: owns eth0 (LAN side - plugged into ds-lan bridge) @@ -445,7 +445,12 @@ This mimics how you might physically plug a cable into a router's LAN port after In NAT mode, Droidspaces writes `/etc/resolv.conf` inside the container, pointing to `1.1.1.1` or `8.8.8.8`. -In gateway mode, Droidspaces does NOT write `resolv.conf` (unless you explicitly pass `--dns`). This is because OpenWRT's `dnsmasq` hands the DNS server address to the container via the DHCP lease. If Droidspaces also wrote a `resolv.conf`, it would conflict with what dnsmasq is providing - the container would use the wrong DNS and bypass OpenWRT's DNS filtering/caching entirely. +In gateway mode, Droidspaces does NOT write a static `resolv.conf` (unless you explicitly pass `--dns`). This is because OpenWRT's `dnsmasq` hands the DNS server address to the container via the DHCP lease. If Droidspaces also wrote a `resolv.conf`, it would conflict with what dnsmasq is providing - the container would use the wrong DNS and bypass OpenWRT's DNS filtering/caching entirely. + +How this is wired depends on the client's init system: + +- **systemd containers:** `/etc/resolv.conf` is symlinked to `/run/systemd/resolve/resolv.conf`, which systemd-resolved populates from the DHCP lease. +- **non-systemd containers:** Droidspaces leaves `/etc/resolv.conf` entirely alone, so the container's own DHCP client (udhcpc/dhclient) writes the gateway-supplied nameserver from the lease. (Earlier builds wrote a hardcoded `1.1.1.1`/`8.8.8.8` here, which silently bypassed the gateway's DNS - that is fixed.) If a minimal rootfs ships no DHCP resolv.conf hook, pass `--dns` to set one explicitly. ### Why bridge-nf-call-iptables is set to 0 @@ -453,19 +458,28 @@ The bridge `ds-lan` carries traffic between OpenWRT and Kali. By default, Linux Setting it to `0` tells Linux: "do not run iptables on bridged traffic." This keeps OpenWRT's firewall as the *only* firewall that sees this traffic, which is exactly what we want. -### The gateway container must be running first +### Start order and automatic self-healing + +All wiring for a gateway-mode client is done **from the host side** by a single function, `gateway_wire_client()`: it ensures the bridge and the gateway-side cable, creates the client's app veth, and moves+renames the peer into the client's namespace as `eth0` (pinned MAC, brought up) — the client's own boot code only brings up `lo`. Because the host owns every step, the same function wires a client whether it is just starting or already running. + +This gives a deliberately simple rule keyed on **gateway liveness**: + +- **Gateway already running when a client starts** → the client wires immediately (its own monitor calls `gateway_wire_client`). +- **Gateway not running when a client starts** → the client wires **nothing at all** (no bridge, no veth, no `eth0`) and just boots. The work is deferred entirely to the gateway. + +Healing is therefore driven by **the gateway itself**, not by the clients. On every boot cycle the gateway container's monitor calls `ds_net_rewire_gateway_clients()`: it scans the running containers, finds the ones that delegate to this gateway, and runs `gateway_wire_client` for each — establishing the gateway-side `eth1` cable and every client's `eth0` into the gateway's *current* namespace. So when the gateway **starts or reboots**, every running client is (re)wired with **no client restart required**. -Start order matters. When a gateway-mode container starts, Droidspaces looks up the gateway container's live process ID to reach its network namespace. If the gateway container is not running at that moment, the network setup fails with a warning and the client container boots anyway - but with no network at all (only loopback). It does not retry on its own. +Skipping all client wiring while the gateway is down (rather than half-wiring a bridge and a danging veth) also closes a race: a client started before its gateway can have its gateway/LAN settings (`--gateway-net`, `--host-bridge`, …) edited before the gateway comes up, and the gateway then wires every client from each client's *current* config — never a stale one. -The same logic applies after a gateway restart. A veth pair dies together: when the gateway container stops, the `eth1` end inside it is destroyed, and that destroys the host-side end too. Existing clients stay plugged into the bridge but have no router anymore. The LAN cable is re-plugged the next time **any** gateway-mode container starts on that segment - so after restarting the gateway, restart one client (or start a new one) to bring the segment back to life. +There is exactly **one actor** (the gateway) doing the wiring, so there is nothing to poll and no thundering herd. Wiring is serialised per segment (an advisory file lock) to keep concurrent client starts and the gateway's re-wire from racing. Both `eth1` (gateway side) and each `eth0` (client side) keep a **stable MAC** and are moved+renamed into their namespace in a single atomic step, so the container's own `netifd`/DHCP sees one persistent device rather than re-initialising a churning one. ### What happens when containers stop Cleanup in gateway mode is deliberately minimal, matching the "plumbing only" philosophy: -- **A client stops:** only that client's own veth (`ds-v`) is removed. The bridge and the gateway's `eth1` stay up, so other clients on the segment are untouched. -- **The gateway stops:** the gateway-side veth disappears with its namespace (see above), but the bridge itself stays. -- The delegated bridge (`ds-lan` etc.) is never torn down by Droidspaces. It is harmless when idle - it has no IP and carries no policy - and persists until you delete it manually or reboot the device. +- **A client stops:** only that client's own veth is removed (gateway clients use the `ds-c` prefix, distinct from NAT's `ds-v`). The bridge and the gateway's `eth1` stay up, so other clients on the segment are untouched. +- **The last client stops while the gateway is still running:** the bridge is **kept** (not reaped). Tearing it down would flap the gateway's live `eth1` carrier and occasionally make netifd report "device initialization failed"; an idle IP-less bridge is harmless and the next client reuses it. +- **The gateway stops:** the gateway-side veth disappears with its namespace. Once no clients remain *and* the gateway is gone, the now-idle bridge is reaped. --- diff --git a/src/boot.c b/src/boot.c index 99e9d07e..4abab540 100644 --- a/src/boot.c +++ b/src/boot.c @@ -136,6 +136,8 @@ int internal_boot(struct ds_config *cfg) { if (nr != (ssize_t)sizeof(hs)) { ds_warn("[NET] Child: incomplete handshake (read %zd, expected %zu)", nr, sizeof(hs)); + } else if (cfg->net_mode == DS_NET_GATEWAY) { + ds_log("[NET] Child: handshake received (gateway mode)"); } else { ds_log("[NET] Child: handshake received: peer=%s ip=%s", hs.peer_name, hs.ip_str); diff --git a/src/include/droidspace.h b/src/include/droidspace.h index 1050af9a..98792b5d 100644 --- a/src/include/droidspace.h +++ b/src/include/droidspace.h @@ -681,6 +681,10 @@ void ds_net_derive_handshake(pid_t init_pid, struct ds_config *cfg, struct ds_net_handshake *hs); void ds_net_cleanup(struct ds_config *cfg, pid_t container_pid); void ds_net_start_route_monitor(void); +/* Gateway self-heal: when the gateway container (re)boots, re-wire its LAN + * cable to every running client that delegates to it, with no client restart. + * Called from the gateway container's monitor on each boot cycle. */ +void ds_net_rewire_gateway_clients(const char *gateway_name, pid_t gateway_pid); int ds_net_disable_tx_checksum(const char *ifname); void parse_cidr(const char *cidr, uint32_t *ip_out, uint32_t *mask_out); @@ -708,6 +712,8 @@ int ds_nl_add_addr4(ds_nl_ctx_t *ctx, const char *ifname, uint32_t ip_be, int ds_nl_add_route4(ds_nl_ctx_t *ctx, uint32_t dst_be, uint8_t dst_len, uint32_t gw_be, int oif_idx); int ds_nl_move_to_netns(ds_nl_ctx_t *ctx, const char *ifname, int netns_fd); +int ds_nl_move_to_netns_named(ds_nl_ctx_t *ctx, const char *ifname, + int netns_fd, const char *newname); int ds_nl_get_iface_table(ds_nl_ctx_t *ctx, const char *ifname, int *table_out); int ds_nl_get_table_default_oif(ds_nl_ctx_t *ctx, int table, char *ifname_out); int ds_nl_get_android_default(ds_nl_ctx_t *ctx, char *ifname_out, diff --git a/src/monitor.c b/src/monitor.c index e902dd2f..49814b44 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -404,11 +404,22 @@ reboot_loop:; /* Send handshake to init */ struct ds_net_handshake hs; ds_net_derive_handshake(netns_pid, cfg, &hs); - ds_log("[NET] Monitor: sending DONE: peer=%s ip=%s", hs.peer_name, - hs.ip_str); + if (cfg->net_mode == DS_NET_GATEWAY) + ds_log("[NET] Monitor: sending DONE (gateway mode: eth0 is wired " + "host-side, IP comes from the gateway's DHCP)"); + else + ds_log("[NET] Monitor: sending DONE: peer=%s ip=%s", hs.peer_name, + hs.ip_str); if (write(cfg->net_done_pipe[1], &hs, sizeof(hs)) != (ssize_t)sizeof(hs)) ds_warn("[NET] Monitor: failed to write handshake to init"); close(cfg->net_done_pipe[1]); + + /* Gateway self-heal: if any running client delegates to THIS container as + * its gateway, (re)plug their LAN cable into our (possibly just-rebooted) + * netns now. Runs on every boot cycle - a cheap no-op when nobody routes + * through us - so a gateway reboot re-wires its clients with no client + * restart. */ + ds_net_rewire_gateway_clients(cfg->container_name, netns_pid); } } diff --git a/src/net/netlink.c b/src/net/netlink.c index 2c885c66..22caa573 100644 --- a/src/net/netlink.c +++ b/src/net/netlink.c @@ -169,7 +169,11 @@ static int ds_nl_talk(ds_nl_ctx_t *ctx, struct nlmsghdr *req) { continue; /* more fragments coming */ return 0; } - break; + /* No message matching our sequence was in this datagram. This happens when + * a prior request left a trailing ACK in the socket buffer, or for a + * multipart reply that spans datagrams. recv() again for our actual reply + * rather than (wrongly) reporting success - the bug that made + * ds_nl_link_exists() return false positives. */ } return 0; } @@ -276,7 +280,11 @@ int ds_nl_link_exists(ds_nl_ctx_t *ctx, const char *ifname) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_type = RTM_GETLINK; - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + /* No NLM_F_ACK: a successful GETLINK already replies with RTM_NEWLINK; adding + * ACK makes the kernel send a *second* (NLMSG_ERROR err=0) message, whose + * leftover in the socket buffer used to desync the next request's reply. + * A missing link still returns NLMSG_ERROR(-ENODEV) regardless of ACK. */ + req.n.nlmsg_flags = NLM_F_REQUEST; req.i.ifi_family = AF_UNSPEC; nl_addattr(&req.n, (int)sizeof(req), IFLA_IFNAME, ifname, (int)strlen(ifname) + 1); @@ -632,6 +640,51 @@ int ds_nl_move_to_netns(ds_nl_ctx_t *ctx, const char *ifname, int netns_fd) { return ds_nl_talk(ctx, &req.n); } +/* --------------------------------------------------------------------------- + * Move an interface into another network namespace AND rename it in the same + * RTM_NEWLINK request (IFLA_NET_NS_FD + IFLA_IFNAME). The kernel applies both + * in a single op, so the device appears in the target netns already carrying + * its final name - there is no transient "raw name then rename" window for a + * daemon (e.g. OpenWrt netifd) in that netns to race against. + * + * The link is brought DOWN first: renaming a running device returns EBUSY on + * some drivers, and a freshly created veth peer is down anyway. The device + * arrives DOWN in the target netns; the caller brings it up there. + * + * Returns 0 on success. On failure (e.g. newname already exists in the target + * netns) nothing is guaranteed to have moved; callers should fall back to a + * plain move + in-netns rename. + * ---------------------------------------------------------------------------*/ +int ds_nl_move_to_netns_named(ds_nl_ctx_t *ctx, const char *ifname, + int netns_fd, const char *newname) { + if (!newname || !newname[0]) + return ds_nl_move_to_netns(ctx, ifname, netns_fd); + + ds_nl_link_down(ctx, ifname); /* allow rename during the move */ + + int idx = ds_nl_get_ifindex(ctx, ifname); + if (idx <= 0) + return -ENODEV; + + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[256]; + } req; + memset(&req, 0, sizeof(req)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_type = RTM_NEWLINK; + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.i.ifi_family = AF_UNSPEC; + req.i.ifi_index = idx; + + nl_addattr(&req.n, (int)sizeof(req), IFLA_NET_NS_FD, &netns_fd, + (int)sizeof(int)); + nl_addattr(&req.n, (int)sizeof(req), IFLA_IFNAME, newname, + (int)strlen(newname) + 1); + return ds_nl_talk(ctx, &req.n); +} + /* --------------------------------------------------------------------------- * Flush stale Droidspaces veth interfaces via RTM_GETLINK dump * diff --git a/src/net/network.c b/src/net/network.c index ef09a980..ee68d3d6 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -21,20 +21,33 @@ #include #include #include +#include #include /* --------------------------------------------------------------------------- * Internal helpers * ---------------------------------------------------------------------------*/ -/* Derive the host-side veth name from a container init PID */ -static void veth_host_name(pid_t pid, char *buf, size_t sz) { - snprintf(buf, sz, "ds-v%d", (int)pid); +/* Host-side veth prefix for an application container. NAT containers use + * "ds-v"; gateway clients use "ds-c" so the NAT-mode "last container" refcount + * (which scans for "ds-v") never miscounts a gateway client as a live NAT + * container and so keeps shared NAT iptables/route rules alive forever. */ +static const char *app_veth_host_prefix(const struct ds_config *cfg) { + return (cfg && cfg->net_mode == DS_NET_GATEWAY) ? "ds-c" : "ds-v"; } -/* Derive the peer (container-side) veth name from a container init PID */ -static void veth_peer_name(pid_t pid, char *buf, size_t sz) { - snprintf(buf, sz, "ds-p%d", (int)pid); +/* Derive the host-side veth name from a container init PID (mode-aware). */ +static void veth_host_name(const struct ds_config *cfg, pid_t pid, char *buf, + size_t sz) { + snprintf(buf, sz, "%s%d", app_veth_host_prefix(cfg), (int)pid); +} + +/* Derive the peer (container-side) veth name from a container init PID. + * Gateway clients use "ds-q" to match the distinct host-side prefix. */ +static void veth_peer_name(const struct ds_config *cfg, pid_t pid, char *buf, + size_t sz) { + const char *p = (cfg && cfg->net_mode == DS_NET_GATEWAY) ? "ds-q" : "ds-p"; + snprintf(buf, sz, "%s%d", p, (int)pid); } /* Derive a deterministic IP from a PID (avoids sequential collisions) */ @@ -83,6 +96,24 @@ static void ds_container_mac(const char *name, uint8_t mac[6]) { mac[5] = (uint8_t)(h2); } +/* Derive a stable MAC for a gateway LAN-side veth from its segment key + * ("{gateway}:{net}"). The gateway's LAN interface (e.g. eth1 inside OpenWrt) + * then keeps the same MAC every time the cable is (re)plugged - across gateway + * reboots and self-heal re-wiring - so netifd sees one persistent device + * instead of re-initialising a new random-MAC device each time. */ +static void ds_segment_mac(const char *key, uint8_t mac[6]) { + uint32_t h1 = ds_net_hash_string(key); + char salted[400]; + snprintf(salted, sizeof(salted), "ds-gwmac:%s", key ? key : ""); + uint32_t h2 = ds_net_hash_string(salted); + mac[0] = 0x02; /* locally administered, unicast */ + mac[1] = (uint8_t)(h1 >> 24); + mac[2] = (uint8_t)(h1 >> 16); + mac[3] = (uint8_t)(h1 >> 8); + mac[4] = (uint8_t)(h1); + mac[5] = (uint8_t)(h2); +} + static void gateway_hash_key(struct ds_config *cfg, char *buf, size_t sz) { const char *gw = (cfg && cfg->gateway_container[0]) ? cfg->gateway_container : "gateway"; @@ -160,8 +191,9 @@ static int ds_netns_rename_up(const char *netns_path, const char *old_name, } if (new_name && new_name[0] && ds_nl_link_exists(ctx, new_name)) { - ds_log("[NET] Gateway: interface %s already exists inside gateway", - new_name); + /* Already present under its final name inside the gateway - the common, + * healthy case: the atomic move+rename created it, or this is an idempotent + * re-entry. Just make sure it is up; the caller logs "uplink ready". */ ds_nl_link_up(ctx, new_name); } else if (old_name && old_name[0] && new_name && new_name[0] && strcmp(old_name, new_name) != 0) { @@ -193,6 +225,8 @@ static int g_current_gw_table = 0; static pthread_mutex_t g_gw_mutex = PTHREAD_MUTEX_INITIALIZER; static int g_route_monitor_sock = -1; static volatile sig_atomic_t g_stop_monitor = 0; +static pthread_t g_route_monitor_tid; +static int g_route_monitor_started = 0; /* guarded by g_gw_mutex */ /* Returns 1 if ifname exists and is both UP and RUNNING. * On Android, the active data interface has IFF_RUNNING set; an interface @@ -252,7 +286,7 @@ static int uplink_name_excluded(const char *ifname) { void ds_net_derive_handshake(pid_t init_pid, struct ds_config *cfg, struct ds_net_handshake *hs) { - veth_peer_name(init_pid, hs->peer_name, sizeof(hs->peer_name)); + veth_peer_name(cfg, init_pid, hs->peer_name, sizeof(hs->peer_name)); /* Use the already-resolved static IP - not the PID-hash fallback. * ip_str is informational on the child side (voided in * setup_veth_child_side_named) but the boot.c log line prints it, @@ -614,8 +648,8 @@ int ds_net_disable_tx_checksum(const char *ifname) { int setup_veth_host_side(struct ds_config *cfg, pid_t child_pid) { char veth_host[IFNAMSIZ], veth_peer[IFNAMSIZ]; - veth_host_name(child_pid, veth_host, sizeof(veth_host)); - veth_peer_name(child_pid, veth_peer, sizeof(veth_peer)); + veth_host_name(cfg, child_pid, veth_host, sizeof(veth_host)); + veth_peer_name(cfg, child_pid, veth_peer, sizeof(veth_peer)); ds_log("Setting up host-side NAT networking for %s (PID %d)...", cfg->container_name, (int)child_pid); @@ -815,147 +849,246 @@ int setup_veth_host_side(struct ds_config *cfg, pid_t child_pid) { } /* --------------------------------------------------------------------------- - * setup_gateway_veth_side - * - * Phase-1 OpenWrt gateway mode. Droidspaces owns only the L2 plumbing: - * - create/reuse a bridge-only LAN with no IP address - * - attach one veth peer to the designated gateway container netns - * - attach one veth peer to the application container netns + * Gateway segment lock * - * No NAT, DHCP, DNS, port-forwarding, Android policy routing, or firewall - * policy is installed here. The gateway container is expected to run the - * routing policy engine (OpenWrt netifd/firewall/dnsmasq/etc.). + * One advisory file lock per delegated LAN segment (keyed on the bridge name). + * Serialises (re)creation of the single shared gateway-side veth + bridge + * across the independent monitor processes that touch a segment - concurrent + * client starts, and the gateway re-wiring its clients on (re)boot - so they + * cannot race each other into EEXIST half-states. * ---------------------------------------------------------------------------*/ -int setup_gateway_veth_side(struct ds_config *cfg, pid_t child_pid) { - if (!cfg || !cfg->gateway_container[0]) { - ds_warn("[NET] Gateway: no gateway container configured"); +static int gateway_segment_lock(const char *bridge) { + char path[PATH_MAX]; + snprintf(path, sizeof(path), "%s/gw_%s.lock", get_net_dir(), bridge); + int fd = open(path, O_CREAT | O_RDWR | O_CLOEXEC, 0600); + if (fd < 0) { + ds_warn("[NET] Gateway: could not open segment lock %s: %s", path, + strerror(errno)); return -1; } - - if (strcmp(cfg->gateway_container, cfg->container_name) == 0) { - ds_warn("[NET] Gateway: refusing to attach container to itself"); + if (flock(fd, LOCK_EX) < 0) { + ds_warn("[NET] Gateway: flock failed on %s: %s", path, strerror(errno)); + close(fd); return -1; } + return fd; +} - const char *gw_if = gateway_lan_ifname(cfg); - if (strlen(gw_if) >= IFNAMSIZ || !gateway_ifname_component_ok(gw_if)) { - ds_warn("[NET] Gateway: invalid gateway interface name '%s'", gw_if); - return -1; - } +static void gateway_segment_unlock(int fd) { + if (fd < 0) + return; + flock(fd, LOCK_UN); + close(fd); +} - struct ds_config gw_cfg; - memset(&gw_cfg, 0, sizeof(gw_cfg)); - gw_cfg.net_ready_pipe[0] = gw_cfg.net_ready_pipe[1] = -1; - gw_cfg.net_done_pipe[0] = gw_cfg.net_done_pipe[1] = -1; - safe_strncpy(gw_cfg.container_name, cfg->gateway_container, - sizeof(gw_cfg.container_name)); +/* --------------------------------------------------------------------------- + * Gateway liveness + * ---------------------------------------------------------------------------*/ - /* Best effort: loading the config gives UUID fallback discovery, but the - * fast pidfile path still works when the config file is unavailable. */ - (void)ds_config_load_by_name(cfg->gateway_container, &gw_cfg); +/* Resolve the gateway container's init pid, or 0 if it is not running. */ +static pid_t gateway_pid_of(const char *name) { + struct ds_config c; + memset(&c, 0, sizeof(c)); + c.net_ready_pipe[0] = c.net_ready_pipe[1] = -1; + c.net_done_pipe[0] = c.net_done_pipe[1] = -1; + safe_strncpy(c.container_name, name, sizeof(c.container_name)); + (void)ds_config_load_by_name(name, &c); + pid_t p = 0; + if (!is_container_running(&c, &p)) + p = 0; + ds_config_free(&c); + return p > 0 ? p : 0; +} - pid_t gw_pid = 0; - if (!is_container_running(&gw_cfg, &gw_pid) || gw_pid <= 0) { - ds_warn("[NET] Gateway: container '%s' is not running", - cfg->gateway_container); - ds_config_free(&gw_cfg); +/* --------------------------------------------------------------------------- + * gateway_ensure_lan_uplink_locked + * + * Ensure the shared half of a delegated LAN segment is wired into the running + * gateway container. The caller holds the segment lock and has already + * confirmed the gateway is up, passing its netns pid: + * - create/reuse the IP-less, policy-neutral bridge + * - ensure the gateway-side veth (ds-g) exists with its peer living in + * the gateway netns as gw_if (e.g. eth1) + * + * Idempotent: a live ds-g implies a live peer (veth pairs die together), + * so a repeat call is a cheap reattach. When the cable is absent we plug a + * fresh one into the gateway's (possibly just-rebooted) netns - this is what + * heals clients after a gateway restart, with no client restart. + * + * Returns 0 when the gateway-side cable is up, -1 on a netlink failure. + * ---------------------------------------------------------------------------*/ + +static int gateway_ensure_lan_uplink_locked(struct ds_config *cfg, + pid_t gw_pid) { + if (!cfg || !cfg->gateway_container[0] || gw_pid <= 0) + return -1; + + const char *gw_if = gateway_lan_ifname(cfg); + if (strlen(gw_if) >= IFNAMSIZ || !gateway_ifname_component_ok(gw_if)) { + ds_warn("[NET] Gateway: invalid gateway interface name '%s'", gw_if); return -1; } - char bridge[IFNAMSIZ]; - char gw_host[IFNAMSIZ], gw_peer[IFNAMSIZ]; - char app_host[IFNAMSIZ], app_peer[IFNAMSIZ]; + char bridge[IFNAMSIZ], gw_host[IFNAMSIZ], gw_peer[IFNAMSIZ]; gateway_bridge_name(cfg, bridge, sizeof(bridge)); gateway_veth_names(cfg, gw_host, sizeof(gw_host), gw_peer, sizeof(gw_peer)); - veth_host_name(child_pid, app_host, sizeof(app_host)); - veth_peer_name(child_pid, app_peer, sizeof(app_peer)); - - ds_log("[NET] Gateway: wiring %s to gateway %s via bridge %s", - cfg->container_name, cfg->gateway_container, bridge); ds_nl_ctx_t *ctx = ds_nl_open(); if (!ctx) { ds_warn("[NET] Gateway: failed to open RTNETLINK socket"); - ds_config_free(&gw_cfg); return -1; } + /* Bridge first, unconditionally: an IP-less, policy-neutral switch. Disable + * bridge netfilter calls so OpenWrt's own firewalling stays the only policy + * authority on the delegated network. */ if (!ds_nl_link_exists(ctx, bridge)) { ds_log("[NET] Gateway: creating delegated LAN bridge %s", bridge); if (ds_nl_create_bridge(ctx, bridge) < 0) { ds_warn("[NET] Gateway: failed to create bridge %s", bridge); ds_nl_close(ctx); - ds_config_free(&gw_cfg); return -1; } } - if (ds_nl_link_up(ctx, bridge) < 0) ds_warn("[NET] Gateway: failed to bring up bridge %s", bridge); - - /* Keep the bridge policy-neutral: no address, no DHCP, no NAT. Disable - * bridge netfilter calls so OpenWrt's own firewalling remains the visible - * policy authority inside the delegated network. */ write_file("/proc/sys/net/bridge/bridge-nf-call-iptables", "0"); write_file("/proc/sys/net/bridge/bridge-nf-call-ip6tables", "0"); - /* Lazily attach a LAN-side interface to the gateway if it is not already - * present. This allows the gateway container to boot with its WAN side - * first, then receive its LAN cable when the first client is attached. */ - if (!ds_nl_link_exists(ctx, gw_host)) { - char gw_netns[PATH_MAX]; - snprintf(gw_netns, sizeof(gw_netns), "/proc/%d/ns/net", (int)gw_pid); + /* Cable already present → live gateway peer → just re-assert master + up. + * This is the idempotent no-op path when the segment is already healthy. */ + if (ds_nl_link_exists(ctx, gw_host)) { + if (ds_nl_set_master(ctx, gw_host, bridge) < 0) + ds_warn("[NET] Gateway: failed to reattach %s to %s", gw_host, bridge); + ds_nl_link_up(ctx, gw_host); + ds_nl_close(ctx); + return 0; + } - ds_log("[NET] Gateway: creating gateway veth %s <-> %s", gw_host, gw_peer); - if (ds_nl_create_veth(ctx, gw_host, gw_peer) < 0) { - ds_warn("[NET] Gateway: failed to create gateway veth pair"); - ds_nl_close(ctx); - ds_config_free(&gw_cfg); - return -1; - } + char gw_netns[PATH_MAX]; + snprintf(gw_netns, sizeof(gw_netns), "/proc/%d/ns/net", (int)gw_pid); - ds_net_disable_tx_checksum(gw_host); - if (ds_nl_set_master(ctx, gw_host, bridge) < 0) - ds_warn("[NET] Gateway: failed to attach %s to %s", gw_host, bridge); - if (ds_nl_link_up(ctx, gw_host) < 0) - ds_warn("[NET] Gateway: failed to bring up %s", gw_host); + ds_log("[NET] Gateway: creating gateway veth %s <-> %s", gw_host, gw_peer); + if (ds_nl_create_veth(ctx, gw_host, gw_peer) < 0) { + ds_warn("[NET] Gateway: failed to create gateway veth pair"); + ds_nl_close(ctx); + return -1; + } - int gw_netns_fd = open(gw_netns, O_RDONLY | O_CLOEXEC); - if (gw_netns_fd < 0) { - ds_warn("[NET] Gateway: failed to open %s: %s", gw_netns, - strerror(errno)); - ds_nl_close(ctx); - ds_config_free(&gw_cfg); - return -1; - } + /* Pin a stable, segment-derived MAC on the gateway-facing peer (becomes gw_if + * inside the gateway) so netifd sees one persistent device across every + * re-plug. Set while down, before the move. */ + { + char key[384]; + uint8_t mac[6]; + gateway_hash_key(cfg, key, sizeof(key)); + ds_segment_mac(key, mac); + if (ds_nl_set_mac(ctx, gw_peer, mac) < 0) + ds_warn("[NET] Gateway: failed to pin MAC on %s", gw_peer); + } + + ds_net_disable_tx_checksum(gw_host); + if (ds_nl_set_master(ctx, gw_host, bridge) < 0) + ds_warn("[NET] Gateway: failed to attach %s to %s", gw_host, bridge); + if (ds_nl_link_up(ctx, gw_host) < 0) + ds_warn("[NET] Gateway: failed to bring up %s", gw_host); + + int gw_netns_fd = open(gw_netns, O_RDONLY | O_CLOEXEC); + if (gw_netns_fd < 0) { + ds_warn("[NET] Gateway: failed to open %s: %s", gw_netns, strerror(errno)); + ds_nl_del_link(ctx, gw_host); /* drop the half-built pair */ + ds_nl_close(ctx); + return -1; + } - int r = ds_nl_move_to_netns(ctx, gw_peer, gw_netns_fd); - close(gw_netns_fd); - if (r < 0) { - ds_warn("[NET] Gateway: failed to move %s into gateway netns", gw_peer); + /* Atomic move+rename: the peer appears inside the gateway already named + * gw_if, so there is no transient raw-name device for netifd to race against + * ("device initialization failed"). Fall back to a plain move on failure. */ + if (ds_nl_move_to_netns_named(ctx, gw_peer, gw_netns_fd, gw_if) != 0) { + ds_warn("[NET] Gateway: atomic move+rename of %s failed - falling back", + gw_peer); + if (ds_nl_move_to_netns(ctx, gw_peer, gw_netns_fd) < 0) { + ds_warn("[NET] Gateway: fallback move of %s into gateway netns failed", + gw_peer); + close(gw_netns_fd); ds_nl_close(ctx); - ds_config_free(&gw_cfg); return -1; } + } + close(gw_netns_fd); + ds_nl_close(ctx); - if (ds_netns_rename_up(gw_netns, gw_peer, gw_if) < 0) - ds_warn("[NET] Gateway: moved %s but could not rename/up it as %s", - gw_peer, gw_if); - } else { - if (ds_nl_set_master(ctx, gw_host, bridge) < 0) - ds_warn("[NET] Gateway: failed to reattach %s to %s", gw_host, bridge); - ds_nl_link_up(ctx, gw_host); + /* Bring it up inside the gateway under its final name (the atomic path + * already renamed it; the fallback path renames here). */ + if (ds_netns_rename_up(gw_netns, gw_peer, gw_if) < 0) + ds_warn("[NET] Gateway: moved %s but could not bring it up as %s", gw_peer, + gw_if); + + ds_log("[NET] Gateway: LAN uplink ready on %s -> %s (%s)", bridge, + cfg->gateway_container, gw_if); + return 0; +} + +/* --------------------------------------------------------------------------- + * gateway_wire_client + * + * Fully wire ONE gateway-mode client into its delegated LAN, entirely from the + * host side. Because the host owns every step - including renaming the peer to + * eth0 and bringing it up *inside* the client netns - this works identically + * whether the client is just starting (its netns fresh, child blocked on the + * handshake) or already running (the gateway came up later and is re-wiring + * it). The gateway-mode child only brings up lo; it never touches eth0. + * + * Under the segment lock: ensure bridge + gateway uplink, create the app veth, + * pin the client's stable MAC, attach the host end to the bridge, then + * move+rename the peer into the client netns as eth0 (up). Returns 0 on + * success. Caller passes the client's init pid and the confirmed-running + * gateway's init pid. + * ---------------------------------------------------------------------------*/ + +static int gateway_wire_client(struct ds_config *cfg, pid_t client_pid, + pid_t gateway_pid) { + if (!cfg || client_pid <= 0 || gateway_pid <= 0) + return -1; + + char bridge[IFNAMSIZ], app_host[IFNAMSIZ], app_peer[IFNAMSIZ]; + gateway_bridge_name(cfg, bridge, sizeof(bridge)); + veth_host_name(cfg, client_pid, app_host, sizeof(app_host)); + veth_peer_name(cfg, client_pid, app_peer, sizeof(app_peer)); + + /* One lock spans the shared uplink AND this client's app-veth attach, so a + * concurrent client's cleanup cannot reap the bridge between them. */ + int lock = gateway_segment_lock(bridge); + int ret = -1; + + if (gateway_ensure_lan_uplink_locked(cfg, gateway_pid) < 0) { + ds_warn("[NET] Gateway: uplink for %s not ready - cannot wire '%s'", bridge, + cfg->container_name); + goto out; } - /* Wire the application container into the delegated LAN bridge. */ - ds_nl_del_link(ctx, app_host); + ds_nl_ctx_t *ctx = ds_nl_open(); + if (!ctx) { + ds_warn("[NET] Gateway: failed to open RTNETLINK socket"); + goto out; + } + + ds_nl_del_link(ctx, app_host); /* drop any stale half from a prior wiring */ ds_log("[NET] Gateway: creating app veth %s <-> %s", app_host, app_peer); if (ds_nl_create_veth(ctx, app_host, app_peer) < 0) { ds_warn("[NET] Gateway: failed to create app veth pair"); ds_nl_close(ctx); - ds_config_free(&gw_cfg); - return -1; + goto out; + } + + /* Pin the client's stable, name-derived MAC on the peer (becomes eth0) before + * the move, so the gateway's DHCP leases see one host across reboots. */ + { + uint8_t mac[6]; + ds_container_mac(cfg->container_name, mac); + if (ds_nl_set_mac(ctx, app_peer, mac) < 0) + ds_warn("[NET] Gateway: failed to pin MAC on %s", app_peer); } ds_net_disable_tx_checksum(app_host); @@ -964,32 +1097,130 @@ int setup_gateway_veth_side(struct ds_config *cfg, pid_t child_pid) { if (ds_nl_link_up(ctx, app_host) < 0) ds_warn("[NET] Gateway: failed to bring up %s", app_host); - char child_netns[PATH_MAX]; - snprintf(child_netns, sizeof(child_netns), "/proc/%d/ns/net", (int)child_pid); - int child_netns_fd = open(child_netns, O_RDONLY | O_CLOEXEC); - if (child_netns_fd < 0) { - ds_warn("[NET] Gateway: failed to open container netns %s: %s", child_netns, + char netns[PATH_MAX]; + snprintf(netns, sizeof(netns), "/proc/%d/ns/net", (int)client_pid); + int netns_fd = open(netns, O_RDONLY | O_CLOEXEC); + if (netns_fd < 0) { + ds_warn("[NET] Gateway: failed to open client netns %s: %s", netns, strerror(errno)); + ds_nl_del_link(ctx, app_host); ds_nl_close(ctx); - ds_config_free(&gw_cfg); + goto out; + } + + /* Atomic move+rename into the client as eth0 (no transient raw-name device + * for the container's own DHCP/networkd to race), with a plain-move fallback. + */ + if (ds_nl_move_to_netns_named(ctx, app_peer, netns_fd, "eth0") != 0) { + ds_warn("[NET] Gateway: atomic move+rename of %s failed - falling back", + app_peer); + if (ds_nl_move_to_netns(ctx, app_peer, netns_fd) < 0) { + ds_warn("[NET] Gateway: move of %s into client netns failed", app_peer); + close(netns_fd); + ds_nl_del_link(ctx, app_host); + ds_nl_close(ctx); + goto out; + } + } + close(netns_fd); + ds_nl_close(ctx); + + if (ds_netns_rename_up(netns, app_peer, "eth0") < 0) + ds_warn("[NET] Gateway: wired '%s' but could not bring up its eth0", + cfg->container_name); + + ret = 0; + ds_log("Gateway: wiring complete for '%s': %s -> %s", cfg->container_name, + bridge, cfg->gateway_container); + +out: + gateway_segment_unlock(lock); + return ret; +} + +/* --------------------------------------------------------------------------- + * setup_gateway_veth_side + * + * Called at client start. OpenWrt gateway mode: Droidspaces owns only the L2 + * plumbing (bridge + veths), never NAT/DHCP/DNS/firewall - the gateway + * container runs that policy. + * + * If the gateway is already running we wire this client now. If it is NOT + * running we skip ALL networking and return: the gateway wires every running + * client itself when it (re)boots (ds_net_rewire_gateway_clients). Deferring + * instead of half-wiring also closes a race - a client started before its + * gateway must not bake in gateway/LAN settings the user may still edit before + * the gateway comes up. + * ---------------------------------------------------------------------------*/ + +int setup_gateway_veth_side(struct ds_config *cfg, pid_t child_pid) { + if (!cfg || !cfg->gateway_container[0]) { + ds_warn("[NET] Gateway: no gateway container configured"); return -1; } - int r = ds_nl_move_to_netns(ctx, app_peer, child_netns_fd); - close(child_netns_fd); - if (r < 0) { - ds_warn("[NET] Gateway: failed to move %s into container netns", app_peer); - ds_nl_close(ctx); - ds_config_free(&gw_cfg); + if (strcmp(cfg->gateway_container, cfg->container_name) == 0) { + ds_warn("[NET] Gateway: refusing to attach container to itself"); return -1; } - ds_nl_close(ctx); - ds_config_free(&gw_cfg); + pid_t gw_pid = gateway_pid_of(cfg->gateway_container); + if (gw_pid <= 0) { + ds_warn("Gateway: '%s' not running - deferring all networking for " + "'%s'; the gateway will wire it when it starts", + cfg->gateway_container, cfg->container_name); + return 0; + } - ds_log("[NET] Gateway: delegated LAN ready: %s -> %s -> %s", - cfg->container_name, bridge, cfg->gateway_container); - return 0; + ds_log("[NET] Gateway: wiring '%s' to gateway '%s'", cfg->container_name, + cfg->gateway_container); + return gateway_wire_client(cfg, child_pid, gw_pid); +} + +/* --------------------------------------------------------------------------- + * ds_net_rewire_gateway_clients + * + * Gateway self-heal, driven by the gateway itself. On every boot the gateway + * container's monitor calls this: it scans the running containers for the ones + * that delegate to this gateway and (re)wires each into the gateway's current + * netns via gateway_wire_client. That one function also idempotently ensures + * the shared LAN uplink, so a single pass covers the gateway-side cable and + * every client's app veth. + * + * This restores clients after the gateway (re)boots - its old netns died and + * took the LAN cable with it - and wires clients that were started while the + * gateway was down. One actor, no client restart. + * ---------------------------------------------------------------------------*/ +void ds_net_rewire_gateway_clients(const char *gateway_name, + pid_t gateway_pid) { + if (!gateway_name || !gateway_name[0] || gateway_pid <= 0) + return; + + char containers_dir[PATH_MAX]; + snprintf(containers_dir, sizeof(containers_dir), "%s/Containers", + get_workspace_dir()); + DIR *d = opendir(containers_dir); + if (!d) + return; + + struct dirent *ent; + while ((ent = readdir(d)) != NULL) { + if (ent->d_name[0] == '.') + continue; + + struct ds_config c = {0}; + if (ds_config_load_by_name(ent->d_name, &c) != 0) + continue; + + pid_t p = 0; + if (c.net_mode == DS_NET_GATEWAY && c.gateway_container[0] && + strcmp(c.gateway_container, gateway_name) == 0 && + is_container_running(&c, &p) && p > 0) + gateway_wire_client(&c, p, gateway_pid); + + ds_config_free(&c); + } + closedir(d); } /* --------------------------------------------------------------------------- @@ -1000,11 +1231,7 @@ int setup_gateway_veth_side(struct ds_config *cfg, pid_t child_pid) { int setup_veth_child_side_named(struct ds_config *cfg, const char *peer_name, const char *ip_str) { - (void)cfg; (void)ip_str; /* IP is now assigned by the container's own DHCP client */ - ds_log("[DEBUG] Child: Configuring isolated networking. Local PID: %d, " - "Peer: %s", - (int)getpid(), peer_name ? peer_name : "(null)"); ds_nl_ctx_t *ctx = ds_nl_open(); if (!ctx) { @@ -1012,6 +1239,26 @@ int setup_veth_child_side_named(struct ds_config *cfg, const char *peer_name, return -1; } + /* Gateway mode: the host monitor owns the entire app-veth wiring - it renames + * the peer to eth0, pins the MAC, and brings it up *inside* this netns - so + * the child only needs loopback. This lets the gateway wire us identically + * whether we are starting now or already running when it (re)boots, and means + * a client started before its gateway simply has no eth0 until the gateway + * comes up and wires it. */ + if (cfg && cfg->net_mode == DS_NET_GATEWAY) { + ds_nl_link_up(ctx, "lo"); + ds_nl_close(ctx); + ds_log("[NET] Child: gateway mode - lo up; gateway container owns " + "eth0/DHCP/routing"); + return 0; + } + + /* NAT mode: the monitor moved the veth peer into this netns under its raw + * name; we rename it to eth0, pin the MAC, and bring it up. */ + ds_log("[DEBUG] Child: configuring container veth (peer %s -> eth0, local " + "PID %d)", + peer_name ? peer_name : "(null)", (int)getpid()); + /* 0. Rename interface to eth0 */ if (peer_name && peer_name[0] && strcmp(peer_name, "eth0") != 0) { ds_log("[DEBUG] Renaming %s to eth0...", peer_name); @@ -1039,10 +1286,7 @@ int setup_veth_child_side_named(struct ds_config *cfg, const char *peer_name, ds_nl_link_up(ctx, "eth0"); ds_nl_close(ctx); - if (cfg && cfg->net_mode == DS_NET_GATEWAY) - ds_log("[NET] Child: eth0 UP - gateway container owns DHCP/routing"); - else - ds_log("[NET] Child: eth0 UP - awaiting DHCP lease from monitor"); + ds_log("[NET] Child: eth0 UP - awaiting DHCP lease from monitor"); return 0; } @@ -1070,9 +1314,23 @@ int setup_veth_child_side_named(struct ds_config *cfg, const char *peer_name, static void setup_resolv_conf(struct ds_config *cfg) { const char *target; - if (cfg->net_mode == DS_NET_GATEWAY && !cfg->dns_servers[0] && - is_systemd_rootfs("/")) { - target = "/run/systemd/resolve/resolv.conf"; + /* Gateway mode with no explicit --dns: DNS belongs to the gateway (OpenWrt + * dnsmasq), advertised in the DHCP lease. Droidspaces must NOT write a + * static resolv.conf or it would bypass the gateway's DNS filtering/caching. + */ + if (cfg->net_mode == DS_NET_GATEWAY && !cfg->dns_servers[0]) { + if (is_systemd_rootfs("/")) { + /* systemd-resolved consumes the lease and publishes the real resolver. */ + target = "/run/systemd/resolve/resolv.conf"; + } else { + /* Non-systemd: leave /etc/resolv.conf to the container's own DHCP client, + * which writes the gateway-supplied nameserver from the lease. Writing a + * hardcoded 1.1.1.1/8.8.8.8 here would silently defeat the gateway's DNS + * (adblock, split-horizon, etc.). Pass --dns to override. */ + ds_log("[NET] Gateway: leaving /etc/resolv.conf to the container's DHCP " + "client (gateway owns DNS)"); + return; + } } else { mkdir("/run/droidspaces", 0755); write_file("/run/droidspaces/resolv.conf", cfg->dns_server_content); @@ -1519,28 +1777,48 @@ static void *route_monitor_loop(void *arg) { } void ds_net_stop_route_monitor(void) { - g_stop_monitor = 1; pthread_mutex_lock(&g_gw_mutex); + int started = g_route_monitor_started; + pthread_t tid = g_route_monitor_tid; + g_stop_monitor = 1; if (g_route_monitor_sock >= 0) shutdown(g_route_monitor_sock, SHUT_RDWR); pthread_mutex_unlock(&g_gw_mutex); + + /* Join so the monitor is fully stopped before cleanup removes the shared + * MASQUERADE / FIB policy rules - otherwise an in-flight do_uplink_reprobe() + * could re-add a rule we just deleted, or rewrite ip_forward after teardown. + */ + if (started) { + pthread_join(tid, NULL); + pthread_mutex_lock(&g_gw_mutex); + g_route_monitor_started = 0; + pthread_mutex_unlock(&g_gw_mutex); + } } void ds_net_start_route_monitor(void) { if (!is_android()) return; + pthread_mutex_lock(&g_gw_mutex); + /* Idempotent: exactly one monitor thread per process. setup_veth_host_side + * calls this on every boot cycle (including reboots, which never stop the + * monitor); without this guard each reboot would spawn another thread, all + * racing the same FIB policy rule. The monitor tracks the host uplink, which + * is independent of the container PID, so a single instance rightly persists + * across the container's reboots. Joinable (default attr) so stop can join. + */ + if (g_route_monitor_started) { + pthread_mutex_unlock(&g_gw_mutex); + return; + } g_stop_monitor = 0; - - pthread_t tid; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if (pthread_create(&tid, &attr, route_monitor_loop, NULL) != 0) + if (pthread_create(&g_route_monitor_tid, NULL, route_monitor_loop, NULL) != 0) ds_warn("[NET] Failed to start route monitor thread: %s", strerror(errno)); - - pthread_attr_destroy(&attr); + else + g_route_monitor_started = 1; + pthread_mutex_unlock(&g_gw_mutex); } /* --------------------------------------------------------------------------- @@ -1557,37 +1835,43 @@ void ds_net_cleanup(struct ds_config *cfg, pid_t container_pid) { pid_t effective_pid = container_pid > 0 ? container_pid : cfg->container_pid; if (effective_pid > 0) { - veth_host_name(effective_pid, veth_host, sizeof(veth_host)); + veth_host_name(cfg, effective_pid, veth_host, sizeof(veth_host)); + + char bridge[IFNAMSIZ]; + gateway_bridge_name(cfg, bridge, sizeof(bridge)); + + /* Hold the segment lock across our veth removal + the client count + + * reap, so a concurrent client's setup (which holds the same lock while + * attaching its veth) cannot slip in between our count and our reap. */ + int lock = gateway_segment_lock(bridge); + ds_nl_del_link(ctx, veth_host); ds_log("[NET] Gateway cleanup: removed %s", veth_host); - /* Refcount the delegated bridge: once the last client veth has left, - * reap the now-empty bridge so idle segments don't linger. */ - char bridge[IFNAMSIZ], gw_host[IFNAMSIZ], gw_peer[IFNAMSIZ]; - gateway_bridge_name(cfg, bridge, sizeof(bridge)); - gateway_veth_names(cfg, gw_host, sizeof(gw_host), gw_peer, - sizeof(gw_peer)); - int clients = ds_nl_count_bridge_members_with_prefix(ctx, bridge, "ds-v"); + int clients = ds_nl_count_bridge_members_with_prefix( + ctx, bridge, app_veth_host_prefix(cfg)); if (clients > 0) { ds_log("[NET] Gateway cleanup: %d client(s) still on %s - keeping " "delegated LAN", clients, bridge); + } else if (gateway_pid_of(cfg->gateway_container) > 0) { + /* No clients left, but the gateway is still up. Do NOT reap the + * bridge: deleting it flaps the gateway's live LAN iface (eth1) + * carrier, and netifd occasionally fails to re-init it ("device + * initialization failed"). The IP-less, policy-free bridge is harmless + * idle and the next client reuses it; the gateway veth stays put. */ + ds_log("[NET] Gateway cleanup: no clients on %s but gateway '%s' is up " + "- keeping bridge to avoid flapping its LAN iface", + bridge, cfg->gateway_container); } else { - /* Reap the empty bridge, but NEVER delete the gateway veth (gw_host): - * its peer is the gateway container's live LAN interface (e.g. eth1), - * and deleting either end destroys the pair - ripping the cable out of - * a still-running gateway. OpenWrt's netifd will not re-init a brand - * new eth1 that reappears under it, so its DHCP/LAN stays dead until - * the gateway is rebooted. Leaving gw_host masterless keeps eth1 - * alive; the next client recreates the bridge and reattaches gw_host - * (setup_gateway_veth_side else-branch). When the gateway container - * itself stops, its netns dies and gw_host vanishes with its peer, - * leaving zero residue. */ + /* No clients and the gateway is gone (its netns death already took the + * gateway veth with its peer) - safe to reap the now-idle bridge. */ ds_nl_del_link(ctx, bridge); - ds_log("[NET] Gateway cleanup: reaped idle delegated LAN bridge %s " - "(kept gateway veth %s)", - bridge, gw_host); + ds_log("[NET] Gateway cleanup: reaped idle delegated LAN bridge %s", + bridge); } + + gateway_segment_unlock(lock); } else { ds_warn("[NET] Gateway cleanup: cannot derive veth name - no valid PID"); } @@ -1612,7 +1896,7 @@ void ds_net_cleanup(struct ds_config *cfg, pid_t container_pid) { ds_warn("[NET] cleanup: cannot derive veth name - no valid PID"); /* still proceed with iptables cleanup */ } else { - veth_host_name(effective_pid, veth_host, sizeof(veth_host)); + veth_host_name(cfg, effective_pid, veth_host, sizeof(veth_host)); ds_nl_del_link(ctx, veth_host); } From d035ce8d6a7e40ac668da69feb586c5ff556cf9f Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Mon, 29 Jun 2026 22:53:56 +0530 Subject: [PATCH 06/25] mount: don't force a full e2fsck on every container start Drop -f from e2fsck: it now exits fast on a clean image and only runs a full repair when the fs is actually marked unclean. Signed-off-by: ravindu644 --- src/mount.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mount.c b/src/mount.c index 0aa3347a..583d2b2f 100644 --- a/src/mount.c +++ b/src/mount.c @@ -1018,10 +1018,14 @@ int mount_rootfs_img(const char *img_path, char *mount_point, size_t mp_size, return -1; } - /* e2fsck: only for ext images */ + /* e2fsck: only for ext images. No -f: e2fsck consults the superblock and + * exits in milliseconds when the fs was unmounted cleanly, replays the + * journal when it was not, and runs a full repair only when the kernel + * flagged an error (errors=remount-ro) or the fs is otherwise marked unclean + * - so a clean start pays nothing instead of a forced full scan every boot. + */ if (strcmp(fstype, "ext4") == 0) { - char *e2fsck_argv[] = {"e2fsck", "-f", "-y", (char *)(uintptr_t)img_path, - NULL}; + char *e2fsck_argv[] = {"e2fsck", "-y", (char *)(uintptr_t)img_path, NULL}; if (run_command_quiet(e2fsck_argv) == 0) ds_log("Image checked and repaired successfully."); } From f702611bf59e643071aae20ea583a35797d90cca Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 00:35:58 +0530 Subject: [PATCH 07/25] net: add --upstream to pin NAT WAN to specific interface(s) Optional manual override for NAT mode. When --upstream is set, the WAN is forced through the listed interface(s) and automatic uplink detection is disabled entirely - it never hops to whatever interface netd marks as the active default network. Within the pinned list it does still fail over in priority (list) order: the route monitor re-resolves on every link/route change and selects the first listed interface that is up and has a default route. So a pin like "wlan0,rmnet*" prefers Wi-Fi and falls back to mobile data when Wi-Fi drops - the hop stays inside the user's chosen set, never outside it. Literals and wildcards are both supported (use rmnet* for mobile data, whose interface number is not stable across reconnects). If no pinned interface is up at start, or the active one disappears mid-run, the FROM rule is removed (so traffic can't leak onto a recycled table) and reinstalled automatically when one returns. Unset = today's automatic detection, unchanged. The CSV parser is shared between the CLI and config loader; the app restores the upstream-interface picker as optional with a pinning hint (string keys renamed to upstream_interface_title/_hint across locales). Signed-off-by: ravindu644 --- .../app/ui/component/UpstreamInterfaceList.kt | 262 ++++++++++++++++++ .../ui/navigation/DroidspacesNavigation.kt | 5 +- .../app/ui/screen/ContainerConfigScreen.kt | 24 +- .../app/ui/screen/EditContainerScreen.kt | 24 ++ .../ui/screen/InstallationSummaryScreen.kt | 6 +- .../ContainerInstallationViewModel.kt | 7 + .../droidspaces/app/util/ContainerManager.kt | 31 +++ .../app/src/main/res/values-de/strings.xml | 6 + .../app/src/main/res/values-in/strings.xml | 6 + .../app/src/main/res/values-it/strings.xml | 6 + .../app/src/main/res/values-ja/strings.xml | 6 + .../app/src/main/res/values-km/strings.xml | 6 + .../app/src/main/res/values-ro/strings.xml | 6 + .../app/src/main/res/values-si/strings.xml | 6 + .../app/src/main/res/values-tr/strings.xml | 6 + .../src/main/res/values-zh-rCN/strings.xml | 6 + .../src/main/res/values-zh-rTW/strings.xml | 6 + Android/app/src/main/res/values/strings.xml | 6 + .../app/src/main/res/xml/locales_config.xml | 1 + src/config.c | 20 +- src/container.c | 17 ++ src/documentation.c | 6 +- src/include/droidspace.h | 10 + src/main.c | 26 +- src/net/network.c | 147 +++++++++- src/utils.c | 31 +++ 26 files changed, 661 insertions(+), 22 deletions(-) create mode 100644 Android/app/src/main/java/com/droidspaces/app/ui/component/UpstreamInterfaceList.kt diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/UpstreamInterfaceList.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/UpstreamInterfaceList.kt new file mode 100644 index 00000000..60e8323f --- /dev/null +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/UpstreamInterfaceList.kt @@ -0,0 +1,262 @@ +package com.droidspaces.app.ui.component + +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.droidspaces.app.R +import com.droidspaces.app.util.ContainerManager +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun UpstreamInterfaceList( + upstreamInterfaces: List, + onInterfacesChange: (List) -> Unit, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + var showUpstreamDialog by remember { mutableStateOf(false) } + var availableUpstreams by remember { mutableStateOf>(emptyList()) } + + LaunchedEffect(Unit) { + availableUpstreams = ContainerManager.listUpstreamInterfaces() + } + + Column(modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp)) { + // Selected interfaces + upstreamInterfaces.forEach { iface -> + Surface( + modifier = Modifier.fillMaxWidth(), + color = MaterialTheme.colorScheme.surfaceContainerHigh, + shape = RoundedCornerShape(20.dp), + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)) + ) { + Row( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = iface, modifier = Modifier.weight(1f), style = MaterialTheme.typography.bodyLarge) + IconButton(onClick = { onInterfacesChange(upstreamInterfaces - iface) }) { + Icon(Icons.Default.Delete, contentDescription = null, tint = MaterialTheme.colorScheme.error) + } + } + } + } + + // Add Button + if (upstreamInterfaces.size < 8) { + val addBtnShape = RoundedCornerShape(16.dp) + Surface( + modifier = Modifier.fillMaxWidth().clip(addBtnShape).clickable( + onClick = { showUpstreamDialog = true } + ), + shape = addBtnShape, + color = MaterialTheme.colorScheme.surfaceContainerLow, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)), + tonalElevation = 0.dp + ) { + Row( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 14.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Center + ) { + Icon(Icons.Default.Add, contentDescription = null, modifier = Modifier.size(18.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(modifier = Modifier.width(8.dp)) + Text( + context.getString(R.string.add_upstream_interface), + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } + } + + if (showUpstreamDialog) { + AddUpstreamDialog( + availableUpstreams = availableUpstreams, + selectedInterfaces = upstreamInterfaces, + onDismiss = { showUpstreamDialog = false }, + onRefresh = { + val newOnes = ContainerManager.listUpstreamInterfaces() + availableUpstreams = newOnes + }, + onAdd = { iface -> + if (!upstreamInterfaces.contains(iface)) { + onInterfacesChange(upstreamInterfaces + iface) + } + showUpstreamDialog = false + } + ) + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun AddUpstreamDialog( + availableUpstreams: List, + selectedInterfaces: List, + onDismiss: () -> Unit, + onRefresh: suspend () -> Unit, + onAdd: (String) -> Unit +) { + val context = LocalContext.current + var customIface by remember { mutableStateOf("") } + var isRefreshing by remember { mutableStateOf(false) } + val scope = rememberCoroutineScope() + + val rotation by animateFloatAsState( + targetValue = if (isRefreshing) 360f else 0f, + animationSpec = if (isRefreshing) { + tween(durationMillis = 600, easing = LinearEasing) + } else { + tween(durationMillis = 0, easing = LinearEasing) + }, + label = "refresh_rotation" + ) + + Dialog( + onDismissRequest = onDismiss, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + Surface( + modifier = Modifier.fillMaxWidth(0.92f).wrapContentHeight(), + shape = RoundedCornerShape(24.dp), + color = MaterialTheme.colorScheme.surfaceContainer, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)), + tonalElevation = 0.dp + ) { + Column( + modifier = Modifier.padding(24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = context.getString(R.string.add_upstream_interface), + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + IconButton( + onClick = { + if (!isRefreshing) { + isRefreshing = true + scope.launch { + val startTime = System.currentTimeMillis() + onRefresh() + val elapsed = System.currentTimeMillis() - startTime + if (elapsed < 600L) delay(600L - elapsed) + isRefreshing = false + } + } + }, + enabled = !isRefreshing + ) { + Icon( + Icons.Default.Refresh, + contentDescription = null, + modifier = Modifier.size(20.dp).graphicsLayer { rotationZ = rotation } + ) + } + } + + if (availableUpstreams.isNotEmpty()) { + Text(context.getString(R.string.available_system_interfaces), style = MaterialTheme.typography.labelMedium) + Box(modifier = Modifier.fillMaxWidth().heightIn(max = 200.dp)) { + FlowRow( + modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + availableUpstreams.forEach { iface -> + OutlinedButton( + onClick = { onAdd(iface) }, + enabled = !selectedInterfaces.contains(iface), + shape = RoundedCornerShape(12.dp), + contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp) + ) { + Text(iface) + } + } + } + } + } + + Spacer(modifier = Modifier.height(4.dp)) + Text(context.getString(R.string.enter_manually), style = MaterialTheme.typography.labelMedium) + OutlinedTextField( + value = customIface, + onValueChange = { customIface = it }, + label = { Text(context.getString(R.string.interface_name_hint)) }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(16.dp), + colors = OutlinedTextFieldDefaults.colors( + unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f), + focusedBorderColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f), + unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow, + focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f) + ) + ) + + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp)) { + Surface( + modifier = Modifier.weight(1f).clip(RoundedCornerShape(14.dp)).clickable(onClick = onDismiss), + shape = RoundedCornerShape(14.dp), + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.06f), + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)), + tonalElevation = 0.dp + ) { + Box(modifier = Modifier.padding(14.dp), contentAlignment = Alignment.Center) { + Text(context.getString(R.string.cancel), style = MaterialTheme.typography.labelLarge, fontWeight = FontWeight.SemiBold) + } + } + Surface( + modifier = Modifier.weight(1f).clip(RoundedCornerShape(14.dp)).clickable( + enabled = customIface.isNotBlank() && selectedInterfaces.size < 8, + onClick = { onAdd(customIface.trim()) } + ), + shape = RoundedCornerShape(14.dp), + color = if (customIface.isNotBlank()) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), + tonalElevation = 0.dp + ) { + Box(modifier = Modifier.padding(14.dp), contentAlignment = Alignment.Center) { + Text( + context.getString(R.string.add), + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.SemiBold, + color = if (customIface.isNotBlank()) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) + ) + } + } + } + } + } + } +} diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/navigation/DroidspacesNavigation.kt b/Android/app/src/main/java/com/droidspaces/app/ui/navigation/DroidspacesNavigation.kt index b55bc7c1..e9cc2f9a 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/navigation/DroidspacesNavigation.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/navigation/DroidspacesNavigation.kt @@ -327,6 +327,7 @@ fun DroidspacesNavigation( initialBlockNestedNs = viewModel.blockNestedNs, initialPrivileged = viewModel.privileged, initialEnvFileContent = viewModel.envFileContent ?: "", + initialUpstreamInterfaces = viewModel.upstreamInterfaces, initialPortForwards = viewModel.portForwards, initialGatewayContainer = viewModel.gatewayContainer, initialGatewayNet = viewModel.gatewayNet, @@ -334,8 +335,8 @@ fun DroidspacesNavigation( initialGatewayBridge = viewModel.gatewayBridge, containerName = viewModel.containerName, installedContainers = sharedContainerViewModel.containerList, - onNext = { netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, forceCgroupv1, blockNestedNs, privileged, envFileContent, portForwards, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge -> - viewModel.setConfig(netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, envFileContent, portForwards, forceCgroupv1, blockNestedNs, privileged, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge) + onNext = { netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, forceCgroupv1, blockNestedNs, privileged, envFileContent, upstreamInterfaces, portForwards, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge -> + viewModel.setConfig(netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, envFileContent, upstreamInterfaces, portForwards, forceCgroupv1, blockNestedNs, privileged, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge) navController.navigate(Screen.SparseImageConfig.route) }, onBack = { diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ContainerConfigScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ContainerConfigScreen.kt index fd97deb9..0a253ff8 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ContainerConfigScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ContainerConfigScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.unit.dp import com.droidspaces.app.ui.component.ToggleCard import com.droidspaces.app.ui.component.DsDropdown import androidx.compose.material.icons.filled.Public +import com.droidspaces.app.ui.component.UpstreamInterfaceList import com.droidspaces.app.ui.component.PortForwardingList import androidx.compose.ui.platform.LocalContext import com.droidspaces.app.R @@ -75,6 +76,7 @@ fun ContainerConfigScreen( initialBlockNestedNs: Boolean = false, initialPrivileged: String = "", initialEnvFileContent: String = "", + initialUpstreamInterfaces: List = emptyList(), initialPortForwards: List = emptyList(), initialGatewayContainer: String = "", initialGatewayNet: String = "", @@ -104,6 +106,7 @@ fun ContainerConfigScreen( blockNestedNs: Boolean, privileged: String, envFileContent: String?, + upstreamInterfaces: List, portForwards: List, gatewayContainer: String, gatewayNet: String, @@ -132,6 +135,7 @@ fun ContainerConfigScreen( var forceCgroupv1 by remember { mutableStateOf(initialForceCgroupv1) } var blockNestedNs by remember { mutableStateOf(initialBlockNestedNs) } var envFileContent by remember { mutableStateOf(initialEnvFileContent) } + var upstreamInterfaces by remember { mutableStateOf(initialUpstreamInterfaces) } var portForwards by remember { mutableStateOf(initialPortForwards) } var privileged by remember { mutableStateOf(initialPrivileged) } var gatewayContainer by remember { mutableStateOf(initialGatewayContainer) } @@ -319,7 +323,7 @@ fun ContainerConfigScreen( .clickable( enabled = canProceed, onClick = { - onNext(netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, forceCgroupv1, blockNestedNs, privileged, if (envFileContent.isBlank()) null else envFileContent, portForwards, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge) + onNext(netMode, disableIPv6, enableAndroidStorage, enableHwAccess, enableGpuMode, enableTermuxX11, tx11ExtraFlags, enableVirgl, virglExtraFlags, enablePulseaudio, selinuxPermissive, volatileMode, bindMounts, dnsServers, runAtBoot, customInit, staticNatIp, forceCgroupv1, blockNestedNs, privileged, if (envFileContent.isBlank()) null else envFileContent, upstreamInterfaces, portForwards, gatewayContainer, gatewayNet, gatewayIface, gatewayBridge) }, indication = androidx.compose.material.ripple.rememberRipple(bounded = true), interactionSource = remember { androidx.compose.foundation.interaction.MutableInteractionSource() } @@ -520,6 +524,24 @@ fun ContainerConfigScreen( ) } + // Upstream Interface (optional pin) + Text( + text = context.getString(R.string.upstream_interface_title), + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = context.getString(R.string.upstream_interface_hint), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + UpstreamInterfaceList( + upstreamInterfaces = upstreamInterfaces, + onInterfacesChange = { upstreamInterfaces = it } + ) + // Port Forwards Text( text = context.getString(R.string.port_forwarding), diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/EditContainerScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/EditContainerScreen.kt index 5380574b..bc31bb1d 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/EditContainerScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/EditContainerScreen.kt @@ -53,6 +53,7 @@ import com.droidspaces.app.ui.component.HardwareAccessDialog import com.droidspaces.app.ui.component.DsDropdown import com.droidspaces.app.ui.component.GatewaySettingsSection import androidx.compose.material.icons.filled.Public +import com.droidspaces.app.ui.component.UpstreamInterfaceList import com.droidspaces.app.ui.component.PortForwardingList import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -106,6 +107,7 @@ fun EditContainerScreen( var dnsServers by remember { mutableStateOf(container.dnsServers) } var runAtBoot by remember { mutableStateOf(container.runAtBoot) } var envFileContent by remember { mutableStateOf(container.envFileContent ?: "") } + var upstreamInterfaces by remember { mutableStateOf(container.upstreamInterfaces) } var portForwards by remember { mutableStateOf(container.portForwards) } var forceCgroupv1 by remember { mutableStateOf(container.forceCgroupv1) } var blockNestedNs by remember { mutableStateOf(container.blockNestedNs) } @@ -145,6 +147,7 @@ fun EditContainerScreen( var savedDnsServers by remember { mutableStateOf(container.dnsServers) } var savedRunAtBoot by remember { mutableStateOf(container.runAtBoot) } var savedEnvFileContent by remember { mutableStateOf(container.envFileContent ?: "") } + var savedUpstreamInterfaces by remember { mutableStateOf(container.upstreamInterfaces) } var savedPortForwards by remember { mutableStateOf(container.portForwards) } var savedForceCgroupv1 by remember { mutableStateOf(container.forceCgroupv1) } var savedBlockNestedNs by remember { mutableStateOf(container.blockNestedNs) } @@ -186,6 +189,7 @@ fun EditContainerScreen( dnsServers != savedDnsServers || runAtBoot != savedRunAtBoot || envFileContent != savedEnvFileContent || + upstreamInterfaces != savedUpstreamInterfaces || portForwards != savedPortForwards || forceCgroupv1 != savedForceCgroupv1 || blockNestedNs != savedBlockNestedNs || @@ -233,6 +237,7 @@ fun EditContainerScreen( dnsServers = dnsServers, runAtBoot = runAtBoot, envFileContent = if (envFileContent.isBlank()) null else envFileContent, + upstreamInterfaces = upstreamInterfaces, portForwards = portForwards, forceCgroupv1 = forceCgroupv1, blockNestedNs = blockNestedNs, @@ -271,6 +276,7 @@ fun EditContainerScreen( savedDnsServers = dnsServers savedRunAtBoot = runAtBoot savedEnvFileContent = envFileContent + savedUpstreamInterfaces = upstreamInterfaces savedPortForwards = portForwards savedForceCgroupv1 = forceCgroupv1 savedBlockNestedNs = blockNestedNs @@ -778,6 +784,24 @@ fun EditContainerScreen( ) } + // Upstream Interface (optional pin) + Text( + text = context.getString(R.string.upstream_interface_title), + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = context.getString(R.string.upstream_interface_hint), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + UpstreamInterfaceList( + upstreamInterfaces = upstreamInterfaces, + onInterfacesChange = { upstreamInterfaces = it } + ) + // Port Forwards Text( text = context.getString(R.string.port_forwarding), diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationSummaryScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationSummaryScreen.kt index 578ddd70..94b91089 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationSummaryScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationSummaryScreen.kt @@ -195,6 +195,10 @@ fun InstallationSummaryScreen( } } + if (config.upstreamInterfaces.isNotEmpty()) { + SummaryItem(stringResource(R.string.upstream_interface_title), config.upstreamInterfaces.joinToString(", "), Icons.Default.Public) + } + if (config.portForwards.isNotEmpty()) { config.portForwards.forEach { forward -> SummaryItem(stringResource(R.string.port_forwarding), "${forward.hostPort} → ${forward.containerPort ?: forward.hostPort} (${forward.proto})", Icons.AutoMirrored.Filled.ArrowForward) @@ -207,7 +211,7 @@ fun InstallationSummaryScreen( !config.runAtBoot && !config.disableIPv6 && !config.enableTermuxX11 && !config.enableVirgl && !config.enablePulseaudio && !config.forceCgroupv1 && !config.blockNestedNs && - config.portForwards.isEmpty() && + config.upstreamInterfaces.isEmpty() && config.portForwards.isEmpty() && config.envFileContent.isNullOrBlank()) { Text( text = stringResource(R.string.no_options_enabled), diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/ContainerInstallationViewModel.kt b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/ContainerInstallationViewModel.kt index 06fbcdf2..9165f6f3 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/ContainerInstallationViewModel.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/ContainerInstallationViewModel.kt @@ -96,6 +96,9 @@ class ContainerInstallationViewModel : ViewModel() { var sparseImageSizeGB: Int by mutableStateOf(8) private set + var upstreamInterfaces: List by mutableStateOf(emptyList()) + private set + var portForwards: List by mutableStateOf(emptyList()) private set @@ -141,6 +144,7 @@ class ContainerInstallationViewModel : ViewModel() { customInit: String, staticNatIp: String, envFileContent: String?, + upstreamInterfaces: List, portForwards: List, forceCgroupv1: Boolean, blockNestedNs: Boolean, @@ -168,6 +172,7 @@ class ContainerInstallationViewModel : ViewModel() { this.customInit = customInit this.staticNatIp = staticNatIp this.envFileContent = envFileContent + this.upstreamInterfaces = upstreamInterfaces this.portForwards = portForwards this.forceCgroupv1 = forceCgroupv1 this.blockNestedNs = blockNestedNs @@ -215,6 +220,7 @@ class ContainerInstallationViewModel : ViewModel() { status = ContainerStatus.STOPPED, // Default status for new container useSparseImage = useSparseImage, sparseImageSizeGB = if (useSparseImage) sparseImageSizeGB else null, + upstreamInterfaces = upstreamInterfaces, portForwards = portForwards, forceCgroupv1 = forceCgroupv1, blockNestedNs = blockNestedNs, @@ -250,6 +256,7 @@ class ContainerInstallationViewModel : ViewModel() { envFileContent = null useSparseImage = true sparseImageSizeGB = 8 + upstreamInterfaces = emptyList() portForwards = emptyList() forceCgroupv1 = false blockNestedNs = false diff --git a/Android/app/src/main/java/com/droidspaces/app/util/ContainerManager.kt b/Android/app/src/main/java/com/droidspaces/app/util/ContainerManager.kt index 31b89878..3c006238 100644 --- a/Android/app/src/main/java/com/droidspaces/app/util/ContainerManager.kt +++ b/Android/app/src/main/java/com/droidspaces/app/util/ContainerManager.kt @@ -50,6 +50,7 @@ data class ContainerInfo( val useSparseImage: Boolean = false, val sparseImageSizeGB: Int? = null, val envFileContent: String? = null, + val upstreamInterfaces: List = emptyList(), val portForwards: List = emptyList(), val forceCgroupv1: Boolean = false, val blockNestedNs: Boolean = false, @@ -87,6 +88,9 @@ data class ContainerInfo( if (bindMounts.isNotEmpty()) { appendLine("bind_mounts=${bindMounts.joinToString(",") { "${it.src}:${it.dest}${if (it.ro) ":ro" else ""}" }}") } + if (netMode == "nat" && upstreamInterfaces.isNotEmpty()) { + appendLine("upstream_interfaces=${upstreamInterfaces.joinToString(",")}") + } if (netMode == "nat" && portForwards.isNotEmpty()) { appendLine("port_forwards=${portForwards.joinToString(",") { val mapping = if (it.containerPort != null) "${it.hostPort}:${it.containerPort}" else it.hostPort @@ -280,6 +284,9 @@ object ContainerManager { } } ?: emptyList() + // Parse upstream interfaces + val upstreamInterfaces = configMap["upstream_interfaces"]?.split(",")?.map { it.trim() }?.filter { it.isNotEmpty() } ?: emptyList() + // Parse port forwards: 8080:80/tcp, 9090:90/udp, 1000-2000/tcp (shorthand) val portForwards = configMap["port_forwards"]?.split(",")?.mapNotNull { pfStr -> try { @@ -323,6 +330,7 @@ object ContainerManager { useSparseImage = useSparseImage, sparseImageSizeGB = sparseImageSizeGB, envFileContent = loadEnvFileContent(containerName), + upstreamInterfaces = upstreamInterfaces, portForwards = portForwards, forceCgroupv1 = configMap["force_cgroupv1"] == "1", blockNestedNs = configMap["block_nested_ns"] == "1", @@ -410,6 +418,29 @@ object ContainerManager { } } + /** + * List active upstream interfaces by scanning all routing tables. + * + * Uses `table all` instead of the default table so that CLAT/Qualcomm + * devices are correctly detected - on these devices every interface has + * its own per-interface routing table and nothing appears in the main + * table, so `ip route show default` returns empty. + */ + suspend fun listUpstreamInterfaces(): List = withContext(Dispatchers.IO) { + try { + val busybox = Constants.BUSYBOX_BINARY_PATH + val cmd = "ip route show table all | $busybox grep '^default' | $busybox awk '{for(i=1;i<=NF;i++) if(\$i==\"dev\") print \$(i+1)}' | $busybox grep -Ev '^(ds-|dummy)' | $busybox sort -u" + val result = Shell.cmd(cmd).exec() + if (result.isSuccess) { + result.out.map { it.trim() }.filter { it.isNotEmpty() } + } else { + emptyList() + } + } catch (e: Exception) { + emptyList() + } + } + /** * Update container configuration. * Only updates the configurable options (hostname, flags), not name or rootfsPath. diff --git a/Android/app/src/main/res/values-de/strings.xml b/Android/app/src/main/res/values-de/strings.xml index 207ba370..60dfe64e 100644 --- a/Android/app/src/main/res/values-de/strings.xml +++ b/Android/app/src/main/res/values-de/strings.xml @@ -325,6 +325,12 @@ NAT Ohne NAT Einstellungen + Upstream-Schnittstelle (optional) + Internetzugang an bestimmte Schnittstelle(n) binden. Leer lassen, um den aktiven Uplink automatisch zu erkennen. + Upstream-Schnittstelle hinzufügen + Verfügbare Systemschnittstellen: + Oder manuell eingeben (Platzhalter werden ebenfalls unterstützt): + Schnittstellenname (z.B. wlan0, v4-rmnet_data*) Portweiterleitung Portweiterleitung hinzufügen Host-Port (1–65535 oder Bereich 100–200) diff --git a/Android/app/src/main/res/values-in/strings.xml b/Android/app/src/main/res/values-in/strings.xml index 1b7d7025..dc1764eb 100644 --- a/Android/app/src/main/res/values-in/strings.xml +++ b/Android/app/src/main/res/values-in/strings.xml @@ -145,6 +145,12 @@ NAT (Default) Tidak ada (terisolasi secara fisik) Pengaturan NAT + Antarmuka Upstream (Opsional) + Sematkan akses internet ke antarmuka tertentu. Kosongkan untuk mendeteksi uplink aktif secara otomatis. + Tambahkan Antarmuka Upstream + Antarmuka Sistem yang Tersedia: + Atau masukkan secara manual (karakter pengganti juga didukung): + Nama Antarmuka (misalnya wlan0, v4-rmnet_data*) Tambahkan Port Forward Port Host (1–65535 atau rentang 100–200) Port Kontainer (1–65535 atau rentang) diff --git a/Android/app/src/main/res/values-it/strings.xml b/Android/app/src/main/res/values-it/strings.xml index ec4c1808..9388075d 100644 --- a/Android/app/src/main/res/values-it/strings.xml +++ b/Android/app/src/main/res/values-it/strings.xml @@ -161,6 +161,12 @@ NAT (Predefinita) Nessuna (Air-gapped) Impostazioni NAT + Interfaccia Upstream (Opzionale) + Vincola la connessione a internet a interfacce specifiche. Lascia vuoto per rilevare automaticamente la connessione attiva. + Aggiungi interfaccia upstream + Interfacce di sistema disponibili: + O inseriscila manualmente (i wildcard sono supportati): + Nome interfaccia (es. wlan0, v4-rmnet_data*) Inoltro Porte Aggiungi Port Forward Porta Host (1-65535 o intervallo 100-200) diff --git a/Android/app/src/main/res/values-ja/strings.xml b/Android/app/src/main/res/values-ja/strings.xml index cd3da14b..98a36584 100644 --- a/Android/app/src/main/res/values-ja/strings.xml +++ b/Android/app/src/main/res/values-ja/strings.xml @@ -245,12 +245,18 @@ SELinuxを記録のみ(permissive)に設定する 旧来のCgroup V1階層構造の利用を強制する 手動デッドロック防止措置 + あるいは手動で入力してください(ワイルドカードも利用できます): + インタフェース名 (wlan0、 v4-rmnet_data*など) Androidの為のLXC風コンテナマネージャ 「%1$s」が選択されました。.tar.xz か .tar.gz 形式のファイルを選択してください。 ファイル形式を検出できませんでした。.tar.xz か .tar.gz 形式のファイルを選択してください。 ディストリビューション ネットワークの方式がNATやNoneであるときには、IPv6は常に無効です。 GPUのノードを隔離された/dev にミラーリングする (完全なるハードウェア透過はしない) + 上流インタフェース(任意) + インターネット接続を特定のインタフェースに固定します。空欄にすると、アクティブな上流回線を自動検出します。 + 上流インタフェースの追加 + 利用可能なシステム・インタフェース: 対称割当の場合は空欄にしてください 不正な範囲形式です(開始-終了) ポート番号は1から65535でなければなりません diff --git a/Android/app/src/main/res/values-km/strings.xml b/Android/app/src/main/res/values-km/strings.xml index 741afe42..71581e00 100644 --- a/Android/app/src/main/res/values-km/strings.xml +++ b/Android/app/src/main/res/values-km/strings.xml @@ -183,6 +183,12 @@ NAT គ្មាន ការកំណត់ NAT + ចំណុចប្រទាក់ខាងលើ (ស្រេចចិត្ត) + ភ្ជាប់អ៊ីនធឺណិតទៅចំណុចប្រទាក់ជាក់លាក់។ ទុកឱ្យនៅទទេ ដើម្បីរកឃើញការតភ្ជាប់សកម្មដោយស្វ័យប្រវត្តិ។ + បន្ថែមចំណុចប្រទាក់ខាងលើ + ចំណុចប្រទាក់ប្រព័ន្ធដែលអាចប្រើបាន៖ + ឬបញ្ចូលវាដោយដៃ (អក្សរជំនួសក៏ត្រូវបានគាំទ្រផងដែរ)៖ + ឈ្មោះចំណុចប្រទាក់ (ឧ. wlan0, v4-rmnet_data*) ការបញ្ជូនបន្តច្រក បន្ថែម​ច្រក​បញ្ជូនបន្ត ច្រកម៉ាស៊ីន (1-65535 ឬចន្លោះពី 100-200) diff --git a/Android/app/src/main/res/values-ro/strings.xml b/Android/app/src/main/res/values-ro/strings.xml index bccee0ad..e82e7408 100644 --- a/Android/app/src/main/res/values-ro/strings.xml +++ b/Android/app/src/main/res/values-ro/strings.xml @@ -126,6 +126,12 @@ NAT (implicit) Niciunul (fără nicio conexiune la rețea) Setări NAT + Interfață de uplink (opțională) + Fixează accesul la internet pe anumite interfețe. Lasă gol pentru a detecta automat uplink-ul activ. + Adaugă interfață de uplink + Interfețe de sistem disponibile: + Sau scrie-le manual (de asemenea, wildcard-urile sunt suportate): + Numele interfeței (de exemplu, wlan0, v4-rmnet_data*) Adaugă port forward Portul gazdei (1-65535 sau intervalul 100-200) Portul container-ului (1-65535 sau interval) diff --git a/Android/app/src/main/res/values-si/strings.xml b/Android/app/src/main/res/values-si/strings.xml index f6d39cd3..b6bb7a68 100644 --- a/Android/app/src/main/res/values-si/strings.xml +++ b/Android/app/src/main/res/values-si/strings.xml @@ -137,6 +137,12 @@ NAT (පෙරනිමිය) කිසිවක් නැත (Air-gapped) NAT සැකසුම් + ප්‍රභව අතුරුමුහුණත (විකල්ප) + අන්තර්ජාල ප්‍රවේශය නිශ්චිත අතුරුමුහුණතකට සම්බන්ධ කරන්න. සක්‍රිය ප්‍රභවය ස්වයංක්‍රීයව හඳුනා ගැනීමට හිස්ව තබන්න. + ප්‍රභව අතුරුමුහුණතක් එක් කරන්න + පද්ධතියේ පවතින අතුරුමුහුණත්: + නැතිනම් එය ඔබම ඇතුළත් කරන්න (Wildcards සඳහාද සහාය දක්වයි): + අතුරුමුහුණතේ නම (උදා: wlan0, v4-rmnet_data*) Port Forwarding Port Forward එකක් එක් කරන්න මව් පද්ධතියේ පෝට් එක (1-65535 හෝ පරාසය 100-200) diff --git a/Android/app/src/main/res/values-tr/strings.xml b/Android/app/src/main/res/values-tr/strings.xml index cd247d10..ff64bac9 100644 --- a/Android/app/src/main/res/values-tr/strings.xml +++ b/Android/app/src/main/res/values-tr/strings.xml @@ -148,6 +148,12 @@ NAT (Izole) Yok NAT Ayarları + Upstream Arayüzü (İsteğe bağlı) + İnternet erişimini belirli arayüze sabitler. Etkin bağlantıyı otomatik algılamak için boş bırakın. + Upstream Arayuzu Ekle + Kullanılabilir Sistem Arayüzleri: + Ya da manuel olarak girin (joker karakterler de desteklenmektedir): + Arayuz Adı (örn. wlan0, v4-rmnet_data*) Port Yönlendirme Port Yonlendirme Ekle Host Bağlantı Noktası (1-65535 veya 100-200 aralığı) diff --git a/Android/app/src/main/res/values-zh-rCN/strings.xml b/Android/app/src/main/res/values-zh-rCN/strings.xml index 7cb5a704..90da5ca4 100644 --- a/Android/app/src/main/res/values-zh-rCN/strings.xml +++ b/Android/app/src/main/res/values-zh-rCN/strings.xml @@ -136,6 +136,12 @@ NAT(默认) 无(完全隔离) NAT 设置 + 上游网络接口(可选) + 将网络访问固定到指定接口。留空则自动检测当前活动的上游接口。 + 添加上游网络接口 + 可用的系统接口: + 或手动输入(支持通配符): + 接口名称(如:wlan0, v4-rmnet_data*) 端口转发 添加端口转发 主机端口(1-65535 或范围 100-200) diff --git a/Android/app/src/main/res/values-zh-rTW/strings.xml b/Android/app/src/main/res/values-zh-rTW/strings.xml index 1b29168a..c79376eb 100644 --- a/Android/app/src/main/res/values-zh-rTW/strings.xml +++ b/Android/app/src/main/res/values-zh-rTW/strings.xml @@ -19,6 +19,7 @@ 留空以使用預設值 此IP 已指派給“%1$s ” 異常 + 或手動輸入(支援通配符): 後端: 未安裝 無法讀取容器資訊 使用稀疏映像檔 @@ -39,6 +40,7 @@ 守護程式模式 核心 失敗%1$s %2$s + 新增上游網路介面 容器資訊 編輯容器:%1$s 選擇使用者 @@ -163,6 +165,7 @@ 無法取得Root 權限 已存在同名容器 無(完全隔離) + 上游網路介面(可選) 停用 使用系統預設方案 輸入容器路徑 @@ -179,6 +182,7 @@ 正在移除舊模組... 強制使用舊版Cgroup V1 層級結構 Android 版本 + 可用的系統介面: 卸載容器失敗 %1$s 範圍格式無效(起始-結束) 容器連接埠(1-65535 或範圍) @@ -257,6 +261,7 @@ , 未啟用任何附加選項 未找到服務 + 介面名稱(如:wlan0, v4-rmnet_data*) 僅允許數字、點和冒號 添加 模組安裝失敗 @@ -273,6 +278,7 @@ 安裝概要 正在檢查root存取權限... 重新整理用戶 + 將網路存取固定到指定介面。留空則自動偵測目前作用中的上游介面。 屏蔽服務 留空表示對稱映射 必須指定大小 diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index d6989198..3f62a305 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -256,6 +256,12 @@ Bridge already used by \'%1$s\'. Use a different LAN name. Interface already used by another segment (\'%1$s\'). Use a different one. NAT Settings + Upstream Interface (Optional) + Pin internet access to specific interface(s). Leave empty to auto-detect the active uplink. + Add Upstream Interface + Available System Interfaces: + Or enter it manually (wildcards are supported too): + Interface Name (e.g. wlan0, v4-rmnet_data*) Port Forwarding Add Port Forward Host Port (1-65535 or range 100-200) diff --git a/Android/app/src/main/res/xml/locales_config.xml b/Android/app/src/main/res/xml/locales_config.xml index f553c1ef..558b4696 100644 --- a/Android/app/src/main/res/xml/locales_config.xml +++ b/Android/app/src/main/res/xml/locales_config.xml @@ -19,6 +19,7 @@ + diff --git a/src/config.c b/src/config.c index f77785ad..5ef0158d 100644 --- a/src/config.c +++ b/src/config.c @@ -393,9 +393,15 @@ int ds_config_load(const char *config_path, struct ds_config *cfg) { else ds_warn("config: ignoring too-long gateway_lan_ifname '%s'", val); } else if (strcmp(key, "upstream_interfaces") == 0) { - /* Legacy key from pre-auto-detection builds - the active uplink is - * now detected automatically. Silently swallow it so it is neither - * applied nor re-saved as an unknown line. */ + /* Comma-separated interface names/wildcards, e.g. "wlan0,rmnet*". When + * present this pins NAT WAN to these interfaces in priority order and + * disables automatic uplink detection. */ + if (ds_parse_iface_csv(val, cfg->upstream_ifaces, + &cfg->upstream_iface_count, + DS_MAX_UPSTREAM_IFACES) > 0) + ds_warn("config: too many upstream_interfaces (max %d) - extra entries " + "ignored", + DS_MAX_UPSTREAM_IFACES); } else if (strcmp(key, "port_forwards") == 0) { /* Comma-separated HOST:CONTAINER[/proto], supporting both single ports * and ranges. Accepted formats: @@ -700,6 +706,14 @@ static void ds_config_serialize_known(FILE *f, struct ds_config *cfg) { fprintf(f, "gateway_lan_ifname=%s\n", cfg->gateway_lan_ifname); } + if (cfg->net_mode == DS_NET_NAT && cfg->upstream_iface_count > 0) { + fprintf(f, "upstream_interfaces="); + for (int i = 0; i < cfg->upstream_iface_count; i++) + fprintf(f, "%s%s", cfg->upstream_ifaces[i], + (i < cfg->upstream_iface_count - 1) ? "," : ""); + fprintf(f, "\n"); + } + if (cfg->net_mode == DS_NET_NAT && cfg->port_forward_count > 0) { fprintf(f, "port_forwards="); for (int i = 0; i < cfg->port_forward_count; i++) { diff --git a/src/container.c b/src/container.c index 7c0be418..5e2b10e1 100644 --- a/src/container.c +++ b/src/container.c @@ -1566,6 +1566,14 @@ int show_info(struct ds_config *cfg, int trust_cfg_pid) { cfg->static_nat_ip[0] ? cfg->static_nat_ip : cfg->nat_container_ip; if (ip[0]) printf("NAT_IP=%s\n", ip); + + if (cfg->upstream_iface_count > 0) { + printf("UPSTREAM_INTERFACES="); + for (int i = 0; i < cfg->upstream_iface_count; i++) + printf("%s%s", cfg->upstream_ifaces[i], + (i < cfg->upstream_iface_count - 1) ? "," : ""); + printf("\n"); + } } else if (cfg->net_mode == DS_NET_GATEWAY) { printf("GATEWAY_CONTAINER=%s\n", cfg->gateway_container); printf("GATEWAY_NET=%s\n", @@ -1729,6 +1737,15 @@ int show_info(struct ds_config *cfg, int trust_cfg_pid) { feat_count++; } + if (cfg->upstream_iface_count > 0) { + printf(" Upstream (pinned): "); + for (int i = 0; i < cfg->upstream_iface_count; i++) + printf("%s%s", cfg->upstream_ifaces[i], + (i < cfg->upstream_iface_count - 1) ? ", " : ""); + printf("\n"); + feat_count++; + } + if (cfg->port_forward_count > 0) { printf(" Port forwards: "); for (int i = 0; i < cfg->port_forward_count; i++) { diff --git a/src/documentation.c b/src/documentation.c index 0c2754b4..9db66e2f 100644 --- a/src/documentation.c +++ b/src/documentation.c @@ -292,7 +292,11 @@ static void print_page(int page, const char *bin) { "start\n", bin); printf(" The internet uplink is detected automatically and tracked " - "in real time.\n\n"); + "in real time.\n"); + printf(" Use --upstream IFACE to pin WAN to a specific interface " + "(disables auto-detect),\n"); + printf(" e.g. --upstream wlan0 to route the container over Wi-Fi while " + "the phone uses mobile data.\n\n"); printf("%sPort Forwarding (NAT only):%s\n", bold, reset); printf(" --port=8080:80 Single port\n"); diff --git a/src/include/droidspace.h b/src/include/droidspace.h index 98792b5d..66e75f30 100644 --- a/src/include/droidspace.h +++ b/src/include/droidspace.h @@ -305,6 +305,7 @@ struct ds_tty_info { * ---------------------------------------------------------------------------*/ #define DS_MAX_PORT_FORWARDS 32 +#define DS_MAX_UPSTREAM_IFACES 32 struct ds_port_forward { uint16_t host_port; /* port on the Android/Linux host */ @@ -429,6 +430,13 @@ struct ds_config { * instead of re-deriving a PID-hash IP. Plain dotted-decimal, no CIDR. */ char static_nat_ip[INET_ADDRSTRLEN]; + /* User-pinned upstream interfaces (--upstream wlan0,rmnet*,...). When set, + * NAT WAN is forced through this list (priority order, literals + wildcards) + * and automatic uplink detection is disabled entirely. Empty = auto-detect. + */ + char upstream_ifaces[DS_MAX_UPSTREAM_IFACES][IFNAMSIZ]; + int upstream_iface_count; + /* Resource limits (0 = unlimited) */ long long memory_limit; /* bytes */ long long cpu_quota; /* us per period */ @@ -445,6 +453,8 @@ struct ds_config { * ---------------------------------------------------------------------------*/ void safe_strncpy(char *dst, const char *src, size_t size); +int ds_parse_iface_csv(const char *val, char ifaces[][IFNAMSIZ], int *count, + int max); char *ds_resolve_path_arg(const char *path); void ds_resolve_argv_paths(int argc, char **argv); long ds_get_container_uptime(pid_t pid); diff --git a/src/main.c b/src/main.c index da191abd..e5484659 100644 --- a/src/main.c +++ b/src/main.c @@ -65,6 +65,10 @@ void print_usage(void) { "ds-NAME)\n" " --nat-ip=IP Assign a fixed IP in 172.28.*.* range (nat " "mode)\n" + " --upstream IFACE Pin NAT WAN to interface(s); disables " + "auto-detect\n" + " comma-separated, wildcards ok, e.g. " + "--upstream wlan0 or wlan0,rmnet*\n" " --port [H:]C[/P] Forward ports (supports ranges and " "symmetric ports)\n" " e.g. --port 22, 80:80/tcp, " @@ -314,7 +318,12 @@ static void enforce_nat_safety(struct ds_config *cfg, int argc, char **argv) { } } - /* --port is only meaningful with --net=nat */ + /* --upstream and --port are only meaningful with --net=nat. --upstream is an + * optional override (auto-detection is the default) - never mandatory. */ + if (cfg->upstream_iface_count > 0 && cfg->net_mode != DS_NET_NAT) { + ds_warn("--upstream is only valid with --net=nat - ignoring"); + cfg->upstream_iface_count = 0; + } if (cfg->port_forward_count > 0 && cfg->net_mode != DS_NET_NAT) { ds_warn("--port is only valid with --net=nat - ignoring"); cfg->port_forward_count = 0; @@ -395,6 +404,7 @@ int main(int argc, char **argv) { {"user", required_argument, 0, 'u'}, {"net", required_argument, 0, 257}, {"port", required_argument, 0, 258}, + {"upstream", required_argument, 0, 259}, {"force-cgroupv1", no_argument, 0, 260}, {"block-nested-namespaces", no_argument, 0, 261}, {"privileged", required_argument, 0, 264}, @@ -943,6 +953,20 @@ int main(int argc, char **argv) { break; } + case 259: { + /* --upstream wlan0,rmnet* (comma-separated, wildcards allowed). Pins + * NAT WAN to this list in priority order and disables auto-detection. */ + if (ds_parse_iface_csv(optarg, cfg.upstream_ifaces, + &cfg.upstream_iface_count, + DS_MAX_UPSTREAM_IFACES) > 0) { + ds_error("Too many --upstream interfaces (max %d)", + DS_MAX_UPSTREAM_IFACES); + ret = 1; + goto cleanup; + } + break; + } + case 260: /* --force-cgroupv1: escape hatch to legacy hierarchy */ cfg.force_cgroupv1 = 1; diff --git a/src/net/network.c b/src/net/network.c index ee68d3d6..111b894f 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -228,6 +228,14 @@ static volatile sig_atomic_t g_stop_monitor = 0; static pthread_t g_route_monitor_tid; static int g_route_monitor_started = 0; /* guarded by g_gw_mutex */ +/* User-pinned upstream interfaces (--upstream). When non-empty, the uplink is + * resolved ONLY from this list (priority order, literals + wildcards) and all + * automatic detection is disabled - an explicit manual override. Copied from + * cfg in setup_veth_host_side(), before routing setup and the monitor read it. + */ +static char g_upstream_ifaces[DS_MAX_UPSTREAM_IFACES][IFNAMSIZ]; +static int g_upstream_count = 0; + /* Returns 1 if ifname exists and is both UP and RUNNING. * On Android, the active data interface has IFF_RUNNING set; an interface * that is physically present but not carrying data loses IFF_RUNNING. */ @@ -580,11 +588,11 @@ static void ds_net_setup_android_routing(ds_nl_ctx_t *ctx) { ds_warn("[NET] Android routing: failed to add tether-return rule (%d)", DS_RULE_PRIO_TETHER); - if (!active_iface[0]) { - ds_warn("[NET] Android routing: no active uplink detected yet - " - "route monitor will install rule when one comes up"); + /* No uplink yet: find_active_uplink() already logged the single "no WAN" + * line. The TO_SUBNET/tether rules above are in place; the route monitor + * installs the FROM rule once an uplink appears. */ + if (!active_iface[0]) return; - } ds_log("[NET] Android routing: active uplink %s → table %d", active_iface, gw_table); @@ -800,7 +808,17 @@ int setup_veth_host_side(struct ds_config *cfg, pid_t child_pid) { } ds_log("[DEBUG] Successfully moved %s to PID %d", veth_peer, (int)child_pid); - /* 7. Android policy routing - uplink is detected automatically */ + /* Cache the user-pinned upstream list (if any) into the globals that the + * routing setup and the route monitor read. Empty list = auto-detect. This + * runs before ds_net_setup_android_routing() and + * ds_net_start_route_monitor(), which both consult g_upstream_*. The count + * is already capped at DS_MAX_UPSTREAM_IFACES by the parsers. */ + g_upstream_count = cfg->upstream_iface_count; + for (int _i = 0; _i < g_upstream_count; _i++) + safe_strncpy(g_upstream_ifaces[_i], cfg->upstream_ifaces[_i], IFNAMSIZ); + + /* 7. Android policy routing - uplink is auto-detected, or pinned via + * --upstream. */ if (is_android()) ds_net_setup_android_routing(ctx); @@ -1473,6 +1491,24 @@ static void log_uplink_change(const char *ifname, int table, g_uplink_fail_warned = 0; /* reset so next failure logs once */ } +/* Single "no uplink" outcome for both modes: warn once (until the next success) + * and clear the last-seen cache. This is the one place the condition is + * reported - callers must not log it again. */ +static void log_no_uplink(void) { + if (!g_uplink_fail_warned) { + if (g_upstream_count > 0) + ds_warn("[NET] Uplink: no pinned --upstream interface is up - container " + "has no WAN; the route monitor will " + "wire it when one appears"); + else + ds_warn( + "[NET] Uplink: no active internet interface found - container has " + "no WAN; the route monitor will wire it when one appears"); + g_uplink_fail_warned = 1; + } + g_last_uplink_iface[0] = '\0'; +} + /* Tier 3 (last resort): scan all interfaces against the built-in uplink * whitelist in priority order; return the first that is RUNNING and has * an IPv4 default route in some table. */ @@ -1501,8 +1537,60 @@ static int scan_uplink_whitelist(ds_nl_ctx_t *ctx, char *iface_out, return -ENOENT; } +/* Manual override: resolve the user-pinned --upstream list in priority order. + * The first entry that is RUNNING and has an IPv4 default route wins. Literal + * entries are checked directly; wildcard entries (containing * or ?) are + * matched with fnmatch() against the live interface list (handles dynamic names + * like rmnet_dataX or v4-rmnet_dataX whose number changes across reconnects). + * No exclude heuristics apply here - the user picked the interface + * deliberately. Returns 0 + fills iface/table, or -ENOENT when none are + * currently available. */ +static int resolve_pinned_uplink(ds_nl_ctx_t *ctx, char *iface_out, + int *table_out) { + char all_ifaces[64][IFNAMSIZ]; + int all_count = -1; /* enumerated lazily, only if a wildcard needs it */ + + for (int i = 0; i < g_upstream_count; i++) { + const char *pat = g_upstream_ifaces[i]; + int is_wild = (strchr(pat, '*') != NULL || strchr(pat, '?') != NULL); + + if (!is_wild) { + int tbl = 0; + if (iface_is_running(pat) && ds_nl_get_iface_table(ctx, pat, &tbl) == 0) { + if (iface_out) + safe_strncpy(iface_out, pat, IFNAMSIZ); + if (table_out) + *table_out = tbl; + return 0; + } + continue; + } + + if (all_count < 0) + all_count = ds_nl_list_ifaces(ctx, all_ifaces, 64); + for (int j = 0; j < all_count; j++) { + if (fnmatch(pat, all_ifaces[j], 0) != 0) + continue; + int tbl = 0; + if (!iface_is_running(all_ifaces[j]) || + ds_nl_get_iface_table(ctx, all_ifaces[j], &tbl) != 0) + continue; + if (iface_out) + safe_strncpy(iface_out, all_ifaces[j], IFNAMSIZ); + if (table_out) + *table_out = tbl; + return 0; + } + } + return -ENOENT; +} + /* Find the interface/table currently providing internet access. - * Fully automatic, three tiers, first hit wins: + * + * If --upstream is set this is a pure manual override: resolve ONLY from that + * list (resolve_pinned_uplink) and disable all auto-detection - the WAN never + * hops to whatever netd marks active. Otherwise it is fully automatic, three + * tiers, first hit wins: * * 1. Android netd default-network FIB rule (fwmark 0x0/0xffff iif lo). * The kernel's ground truth - swapped atomically on every handoff, @@ -1520,6 +1608,21 @@ static int find_active_uplink(ds_nl_ctx_t *ctx, char *iface_out, char name[IFNAMSIZ] = {0}; int tbl = 0; + /* Manual override: pinned --upstream list only, no fallback to auto-detect. + */ + if (g_upstream_count > 0) { + if (resolve_pinned_uplink(ctx, name, &tbl) == 0) { + log_uplink_change(name, tbl, "pinned"); + if (iface_out) + safe_strncpy(iface_out, name, IFNAMSIZ); + if (table_out) + *table_out = tbl; + return 0; + } + log_no_uplink(); + return -ENOENT; + } + /* Tier 1: netd default-network rule (Android only - the rule simply * does not exist elsewhere, but skip the dump cost off-Android). */ if (is_android() && ds_nl_get_android_default(ctx, name, &tbl) == 0 && @@ -1556,12 +1659,7 @@ static int find_active_uplink(ds_nl_ctx_t *ctx, char *iface_out, return 0; } - if (!g_uplink_fail_warned) { - ds_warn("[NET] Uplink detection: no active internet interface found - " - "will keep probing"); - g_uplink_fail_warned = 1; - } - g_last_uplink_iface[0] = '\0'; + log_no_uplink(); return -ENOENT; } @@ -1575,7 +1673,30 @@ static void do_uplink_reprobe(void) { int new_table = 0; if (find_active_uplink(ctx, new_iface, &new_table) != 0) { - /* No uplink active yet - leave current rule in place */ + /* No uplink available. */ + if (g_upstream_count > 0) { + /* Pinned mode: the forced interface is gone. Tear the FROM rule down so + * container traffic is NOT silently re-routed onto a table the kernel may + * recycle for a different network (no hopping / no leak). When the + * pinned interface returns, a later reprobe reinstalls the rule. */ + pthread_mutex_lock(&g_gw_mutex); + int old_table = g_current_gw_table; + pthread_mutex_unlock(&g_gw_mutex); + if (old_table > 0) { + uint32_t subnet_be, mask_be; + parse_cidr(DS_DEFAULT_SUBNET, &subnet_be, &mask_be); + (void)mask_be; + ds_nl_del_rule4(ctx, subnet_be, DS_NAT_PREFIX, 0, 0, old_table, + DS_RULE_PRIO_FROM_SUBNET); + pthread_mutex_lock(&g_gw_mutex); + g_current_gw_table = 0; + pthread_mutex_unlock(&g_gw_mutex); + ds_log("[NET] Route monitor: pinned uplink gone - removed FROM rule " + "(container WAN is down until it returns)"); + } + } + /* Auto mode leaves the current rule in place (avoid flapping on + * transients); pinned mode has already torn it down above. */ ds_nl_close(ctx); return; } diff --git a/src/utils.c b/src/utils.c index 75e73c1b..dfe77e80 100644 --- a/src/utils.c +++ b/src/utils.c @@ -30,6 +30,37 @@ void safe_strncpy(char *dst, const char *src, size_t size) { snprintf(dst, size, "%s", src); } +/* Append comma-separated interface names/wildcards from `val` to ifaces[], + * trimming surrounding whitespace and skipping empty or over-long (>= IFNAMSIZ) + * tokens. Duplicates are kept - a pinned list is priority-ordered and + * first-match-wins, so a repeat is a harmless re-check. *count is advanced up + * to `max`; the return value is the number of tokens dropped because the array + * was already full (0 = all fit), letting the caller warn or fail as it likes. + */ +int ds_parse_iface_csv(const char *val, char ifaces[][IFNAMSIZ], int *count, + int max) { + char copy[1024]; + safe_strncpy(copy, val, sizeof(copy)); + int dropped = 0; + char *sp; + for (char *tok = strtok_r(copy, ",", &sp); tok; + tok = strtok_r(NULL, ",", &sp)) { + while (*tok == ' ' || *tok == '\t') + tok++; + char *end = tok + strlen(tok) - 1; + while (end > tok && (*end == ' ' || *end == '\t')) + *end-- = '\0'; + if (!tok[0] || strlen(tok) >= IFNAMSIZ) + continue; + if (*count >= max) { + dropped++; + continue; + } + safe_strncpy(ifaces[(*count)++], tok, IFNAMSIZ); + } + return dropped; +} + /* Mirrors ContainerManager.sanitizeContainerName() in the Android app. * Replaces spaces with dashes so directory names are consistent. */ void sanitize_container_name(const char *name, char *out, size_t size) { From 9ac6ed3d1a6bb31b9925eb852d0ce2a7083a99b0 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 11:06:09 +0530 Subject: [PATCH 08/25] net: re-assert ip_forward on every platform, not just Android Signed-off-by: ravindu644 --- src/net/network.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/net/network.c b/src/net/network.c index 111b894f..cfbbc50a 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -1779,16 +1779,18 @@ static void *route_monitor_loop(void *arg) { struct pollfd pfd = {.fd = sock, .events = POLLIN}; while (!g_stop_monitor) { - /* Enforce IPv4 forwarding in real-time. Since Android kernels do not - * broadcast POLLERR/inotify events for /proc/sys/ memory variables, - * we must check it periodically. Reading a 1-byte procfs memory flag - * takes < 1 microsecond, costing 0% CPU. */ - if (is_android() && g_current_gw_table > 0) { + /* Enforce IPv4 forwarding in real-time. If ip_forward ever flips to 0 + * the NAT'd container loses all WAN traffic, so re-assert it on every + * cycle regardless of platform - Android's netd is the usual culprit, + * but a desktop firewall/sysctl reload or another tool can clear it too. + * The kernel does not broadcast POLLERR/inotify events for /proc/sys/ + * memory variables, so we must poll; reading a 1-byte procfs flag takes + * < 1 microsecond, costing 0% CPU. */ + if (g_current_gw_table > 0) { char val[4] = {0}; if (read_file("/proc/sys/net/ipv4/ip_forward", val, sizeof(val)) > 0 && val[0] == '0') { - ds_log("[NET] Route monitor: ip_forward was disabled by Android, " - "re-enabling..."); + ds_log("[NET] Route monitor: ip_forward was disabled - re-enabling..."); write_file("/proc/sys/net/ipv4/ip_forward", "1\n"); } } From 371ffd89d05d55eb965a4451e9736a66a44e86e9 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 11:17:27 +0530 Subject: [PATCH 09/25] app: block back gesture on backend install screen, force Continue button Signed-off-by: ravindu644 --- .../app/ui/screen/InstallationScreen.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationScreen.kt index 4790a02d..8aa66ac8 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/InstallationScreen.kt @@ -1,6 +1,7 @@ package com.droidspaces.app.ui.screen import androidx.compose.ui.graphics.Color +import androidx.activity.compose.BackHandler import androidx.compose.animation.core.* import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -8,6 +9,7 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.* @@ -49,6 +51,15 @@ fun InstallationScreen( var isInstallingModule by remember { mutableStateOf(false) } var rebootRecommended by remember { mutableStateOf(false) } + // Completely block the back gesture in every state. This screen must be + // left only via the Continue button, whose handler decides the next + // destination and triggers the post-install refresh. A raw back-stack pop + // would skip that and strand the user on a stale screen (e.g. the + // "update available" card still showing after the update finished). + BackHandler(enabled = true) { + // Intentionally no-op while installing, on success and on error. + } + // Check backend status and determine what to install LaunchedEffect(Unit) { if (!isInstalling && !isSuccess) { @@ -156,7 +167,9 @@ fun InstallationScreen( Scaffold( containerColor = Color.Transparent, bottomBar = { - if (isSuccess) { + // Show the Continue button once the work is finished, whether it + // succeeded or failed - it is the only accepted way off this screen. + if (isSuccess || errorMessage != null) { val btnShape = RoundedCornerShape(20.dp) Surface( modifier = Modifier.fillMaxWidth(), @@ -186,7 +199,7 @@ fun InstallationScreen( Box(modifier = Modifier.padding(vertical = 16.dp), contentAlignment = Alignment.Center) { Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { Icon( - imageVector = Icons.Default.Check, + imageVector = if (isSuccess) Icons.Default.Check else Icons.AutoMirrored.Filled.ArrowForward, contentDescription = null, modifier = Modifier.size(18.dp), tint = MaterialTheme.colorScheme.onPrimary From f30f46749478678d8b8dd17e16c86cb6ff523c95 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 12:47:36 +0530 Subject: [PATCH 10/25] net: dedupe NAT/gateway helpers (iptables ACCEPT, MAC, link up/down) Signed-off-by: ravindu644 --- src/net/iptables.c | 298 ++++++++++++++++++--------------------------- src/net/netlink.c | 27 ++-- src/net/network.c | 53 ++++---- 3 files changed, 148 insertions(+), 230 deletions(-) diff --git a/src/net/iptables.c b/src/net/iptables.c index 4736d5d2..da4e9c7d 100644 --- a/src/net/iptables.c +++ b/src/net/iptables.c @@ -803,6 +803,85 @@ int ds_ipt_ensure_masquerade(const char *src_cidr) { return run_command_quiet(argv); } +/* --------------------------------------------------------------------------- + * Internal: insert_iface_accept + * + * Insert "-I 1 [-i|-o] -j ACCEPT" into the filter table, + * idempotently, via the raw socket API with a per-rule binary fallback. + * is_out selects the egress (outiface) match; otherwise it matches ingress + * (iniface). Returns 0 when the rule is present (inserted, already there, or + * added via the binary fallback), or a negative errno when the table itself + * could not be read (the caller decides whether that warrants a full binary + * fallback). + * ---------------------------------------------------------------------------*/ + +static int insert_iface_accept(int fd, unsigned int hook, const char *chain, + const char *iface, int is_out) { + struct ipt_getinfo info; + unsigned char *base = NULL; + int ret = get_table(fd, "filter", &info, &base); + if (ret < 0) + return ret; + + const char *want_in = is_out ? NULL : iface; + const char *want_out = is_out ? iface : NULL; + + if (rule_exists_in_hook(&info, ENTRIES_BLOB(base), hook, want_in, want_out, 0, + 0, "ACCEPT")) { + ds_log("[IPT] %s -%c %s ACCEPT already present", chain, is_out ? 'o' : 'i', + iface); + free(base); + return 0; + } + + unsigned char rule_buf[XT_ALIGN(sizeof(struct ipt_entry)) + + XT_ALIGN(sizeof(struct xt_standard_target))]; + memset(rule_buf, 0, sizeof(rule_buf)); + + struct ipt_entry *re = (struct ipt_entry *)rule_buf; + struct xt_standard_target *st = + (struct xt_standard_target *)(rule_buf + + XT_ALIGN(sizeof(struct ipt_entry))); + + if (is_out) { + safe_strncpy(re->ip.outiface, iface, IFNAMSIZ); + memset(re->ip.outiface_mask, 0xff, strlen(iface) + 1); + } else { + safe_strncpy(re->ip.iniface, iface, IFNAMSIZ); + memset(re->ip.iniface_mask, 0xff, strlen(iface) + 1); + } + re->target_offset = (__u16)XT_ALIGN(sizeof(struct ipt_entry)); + re->next_offset = (__u16)sizeof(rule_buf); + + st->target.u.target_size = (__u16)XT_ALIGN(sizeof(struct xt_standard_target)); + st->target.u.user.name[0] = '\0'; + st->target.u.user.revision = 0; + st->verdict = -NF_ACCEPT - 1; + + ret = insert_rule_at_hook(fd, "filter", &info, ENTRIES_BLOB(base), hook, + rule_buf, sizeof(rule_buf)); + free(base); + + if (ret == 0) { + ds_log("[IPT] %s -%c %s ACCEPT inserted", chain, is_out ? 'o' : 'i', iface); + return 0; + } + + ds_log("[IPT] Raw insert %s -%c %s failed (ret=%d), using binary", chain, + is_out ? 'o' : 'i', iface, ret); + char *a[] = {"iptables", + "-I", + (char *)(uintptr_t)chain, + "1", + is_out ? "-o" : "-i", + (char *)(uintptr_t)iface, + "-j", + "ACCEPT", + NULL}; + run_command_quiet(a); + return 0; +} + /* --------------------------------------------------------------------------- * Public API: ds_ipt_ensure_forward_accept * @@ -820,119 +899,25 @@ int ds_ipt_ensure_forward_accept(const char *iface) { if (!should_use_raw_api()) goto binary_fallback_fwd; - int fd = open_raw_socket(); - if (fd < 0) - goto binary_fallback_fwd; - - /* -i iface */ { - struct ipt_getinfo info; - unsigned char *base = NULL; - int ret = get_table(fd, "filter", &info, &base); - if (ret < 0) { - close(fd); - if (ret == -ENOENT || ret == -ENOPROTOOPT || ret == -EACCES || - ret == -EOPNOTSUPP) - goto binary_fallback_fwd; - return ret; - } + int fd = open_raw_socket(); + if (fd < 0) + goto binary_fallback_fwd; - if (!rule_exists_in_hook(&info, ENTRIES_BLOB(base), NF_INET_FORWARD, iface, - NULL, 0, 0, "ACCEPT")) { - unsigned char rule_buf[XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct xt_standard_target))]; - memset(rule_buf, 0, sizeof(rule_buf)); - - struct ipt_entry *re = (struct ipt_entry *)rule_buf; - struct xt_standard_target *st = - (struct xt_standard_target *)(rule_buf + - XT_ALIGN(sizeof(struct ipt_entry))); - - safe_strncpy(re->ip.iniface, iface, IFNAMSIZ); - memset(re->ip.iniface_mask, 0xff, strlen(iface) + 1); - re->target_offset = (__u16)XT_ALIGN(sizeof(struct ipt_entry)); - re->next_offset = (__u16)sizeof(rule_buf); - - st->target.u.target_size = - (__u16)XT_ALIGN(sizeof(struct xt_standard_target)); - st->target.u.user.name[0] = '\0'; - st->target.u.user.revision = 0; - st->verdict = -NF_ACCEPT - 1; - - ret = insert_rule_at_hook(fd, "filter", &info, ENTRIES_BLOB(base), - NF_INET_FORWARD, rule_buf, sizeof(rule_buf)); - if (ret == 0) { - ds_log("[IPT] FORWARD -i %s ACCEPT inserted", iface); - } else { - ds_log("[IPT] Raw insert -i %s failed (ret=%d), using binary", iface, - ret); - char *a[] = {"iptables", "-I", "FORWARD", - "1", "-i", (char *)(uintptr_t)iface, - "-j", "ACCEPT", NULL}; - run_command_quiet(a); - } - } else { - ds_log("[IPT] FORWARD -i %s ACCEPT already present", iface); - } - free(base); - } + int ret = insert_iface_accept(fd, NF_INET_FORWARD, "FORWARD", iface, 0); + if (ret == 0) + ret = insert_iface_accept(fd, NF_INET_FORWARD, "FORWARD", iface, 1); + close(fd); - /* Re-read table for the second insert */ - { - struct ipt_getinfo info; - unsigned char *base = NULL; - int ret = get_table(fd, "filter", &info, &base); if (ret < 0) { - close(fd); if (ret == -ENOENT || ret == -ENOPROTOOPT || ret == -EACCES || ret == -EOPNOTSUPP) goto binary_fallback_fwd; return ret; } - - if (!rule_exists_in_hook(&info, ENTRIES_BLOB(base), NF_INET_FORWARD, NULL, - iface, 0, 0, "ACCEPT")) { - unsigned char rule_buf[XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct xt_standard_target))]; - memset(rule_buf, 0, sizeof(rule_buf)); - - struct ipt_entry *re = (struct ipt_entry *)rule_buf; - struct xt_standard_target *st = - (struct xt_standard_target *)(rule_buf + - XT_ALIGN(sizeof(struct ipt_entry))); - - safe_strncpy(re->ip.outiface, iface, IFNAMSIZ); - memset(re->ip.outiface_mask, 0xff, strlen(iface) + 1); - re->target_offset = (__u16)XT_ALIGN(sizeof(struct ipt_entry)); - re->next_offset = (__u16)sizeof(rule_buf); - - st->target.u.target_size = - (__u16)XT_ALIGN(sizeof(struct xt_standard_target)); - st->target.u.user.name[0] = '\0'; - st->target.u.user.revision = 0; - st->verdict = -NF_ACCEPT - 1; - - ret = insert_rule_at_hook(fd, "filter", &info, ENTRIES_BLOB(base), - NF_INET_FORWARD, rule_buf, sizeof(rule_buf)); - if (ret == 0) { - ds_log("[IPT] FORWARD -o %s ACCEPT inserted", iface); - } else { - ds_log("[IPT] Raw insert -o %s failed (ret=%d), using binary", iface, - ret); - char *a[] = {"iptables", "-I", "FORWARD", - "1", "-o", (char *)(uintptr_t)iface, - "-j", "ACCEPT", NULL}; - run_command_quiet(a); - } - } else { - ds_log("[IPT] FORWARD -o %s ACCEPT already present", iface); - } - free(base); + return 0; } - close(fd); - return 0; - binary_fallback_fwd: ds_log("[IPT] FORWARD ACCEPT binary fallback for iface=%s", iface); { @@ -961,62 +946,23 @@ int ds_ipt_ensure_input_accept(const char *iface) { if (!should_use_raw_api()) goto binary_fallback_inp; - int fd = open_raw_socket(); - if (fd < 0) - goto binary_fallback_inp; - - struct ipt_getinfo info; - unsigned char *base = NULL; - int ret = get_table(fd, "filter", &info, &base); - if (ret < 0) { - close(fd); - if (ret == -ENOENT || ret == -ENOPROTOOPT || ret == -EACCES || - ret == -EOPNOTSUPP) + { + int fd = open_raw_socket(); + if (fd < 0) goto binary_fallback_inp; - return ret; - } - - if (!rule_exists_in_hook(&info, ENTRIES_BLOB(base), NF_INET_LOCAL_IN, iface, - NULL, 0, 0, "ACCEPT")) { - unsigned char rule_buf[XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct xt_standard_target))]; - memset(rule_buf, 0, sizeof(rule_buf)); - - struct ipt_entry *re = (struct ipt_entry *)rule_buf; - struct xt_standard_target *st = - (struct xt_standard_target *)(rule_buf + - XT_ALIGN(sizeof(struct ipt_entry))); - safe_strncpy(re->ip.iniface, iface, IFNAMSIZ); - memset(re->ip.iniface_mask, 0xff, strlen(iface) + 1); - re->target_offset = (__u16)XT_ALIGN(sizeof(struct ipt_entry)); - re->next_offset = (__u16)sizeof(rule_buf); - - st->target.u.target_size = - (__u16)XT_ALIGN(sizeof(struct xt_standard_target)); - st->target.u.user.name[0] = '\0'; - st->target.u.user.revision = 0; - st->verdict = -NF_ACCEPT - 1; + int ret = insert_iface_accept(fd, NF_INET_LOCAL_IN, "INPUT", iface, 0); + close(fd); - ret = insert_rule_at_hook(fd, "filter", &info, ENTRIES_BLOB(base), - NF_INET_LOCAL_IN, rule_buf, sizeof(rule_buf)); - if (ret == 0) { - ds_log("[IPT] INPUT -i %s ACCEPT inserted", iface); - } else { - ds_log("[IPT] Raw insert INPUT failed (ret=%d), binary fallback", ret); - char *a[] = {"iptables", "-I", "INPUT", - "1", "-i", (char *)(uintptr_t)iface, - "-j", "ACCEPT", NULL}; - run_command_quiet(a); + if (ret < 0) { + if (ret == -ENOENT || ret == -ENOPROTOOPT || ret == -EACCES || + ret == -EOPNOTSUPP) + goto binary_fallback_inp; + return ret; } - } else { - ds_log("[IPT] INPUT -i %s ACCEPT already present", iface); + return 0; } - free(base); - close(fd); - return 0; - binary_fallback_inp: { char *a[] = {"iptables", "-I", "INPUT", "1", "-i", (char *)(uintptr_t)iface, @@ -1328,6 +1274,25 @@ static int pf_state_remove(const char *container_ip) { return 1; } +/* Format the three iptables strings for one port-forward entry. Range entries + * (host_port_end set) use START:END for --dport and START-END for + * --to-destination; single ports use the plain number. */ +static void pf_fmt_ports(const struct ds_port_forward *pf, + const char *container_ip, char host_port_str[16], + char cont_port_str[16], char to_dest[80]) { + if (pf->host_port_end) { + snprintf(host_port_str, 16, "%u:%u", pf->host_port, pf->host_port_end); + snprintf(cont_port_str, 16, "%u:%u", pf->container_port, + pf->container_port_end); + snprintf(to_dest, 80, "%s:%u-%u", container_ip, pf->container_port, + pf->container_port_end); + } else { + snprintf(host_port_str, 16, "%u", pf->host_port); + snprintf(cont_port_str, 16, "%u", pf->container_port); + snprintf(to_dest, 80, "%s:%u", container_ip, pf->container_port); + } +} + /* --------------------------------------------------------------------------- * Public API: ds_ipt_add_portforwards * @@ -1366,20 +1331,7 @@ int ds_ipt_add_portforwards(struct ds_config *cfg, const char *container_ip) { struct ds_port_forward *pf = &cfg->port_forwards[i]; char host_port_str[16], cont_port_str[16], to_dest[80]; - if (pf->host_port_end) { - /* Range syntax: START:END for --dport, START-END for --to-destination */ - snprintf(host_port_str, sizeof(host_port_str), "%u:%u", pf->host_port, - pf->host_port_end); - snprintf(cont_port_str, sizeof(cont_port_str), "%u:%u", - pf->container_port, pf->container_port_end); - snprintf(to_dest, sizeof(to_dest), "%s:%u-%u", container_ip, - pf->container_port, pf->container_port_end); - } else { - snprintf(host_port_str, sizeof(host_port_str), "%u", pf->host_port); - snprintf(cont_port_str, sizeof(cont_port_str), "%u", pf->container_port); - snprintf(to_dest, sizeof(to_dest), "%s:%u", container_ip, - pf->container_port); - } + pf_fmt_ports(pf, container_ip, host_port_str, cont_port_str, to_dest); ds_log("portforward: %s %s -> %s", pf->proto, host_port_str, to_dest); @@ -1511,19 +1463,7 @@ int ds_ipt_remove_portforwards(struct ds_config *cfg) { struct ds_port_forward *pf = &cfg->port_forwards[i]; char host_port_str[16], cont_port_str[16], to_dest[80]; - if (pf->host_port_end) { - snprintf(host_port_str, sizeof(host_port_str), "%u:%u", pf->host_port, - pf->host_port_end); - snprintf(cont_port_str, sizeof(cont_port_str), "%u:%u", - pf->container_port, pf->container_port_end); - snprintf(to_dest, sizeof(to_dest), "%s:%u-%u", container_ip, - pf->container_port, pf->container_port_end); - } else { - snprintf(host_port_str, sizeof(host_port_str), "%u", pf->host_port); - snprintf(cont_port_str, sizeof(cont_port_str), "%u", pf->container_port); - snprintf(to_dest, sizeof(to_dest), "%s:%u", container_ip, - pf->container_port); - } + pf_fmt_ports(pf, container_ip, host_port_str, cont_port_str, to_dest); /* addrtype variant */ char *del_at[] = { diff --git a/src/net/netlink.c b/src/net/netlink.c index 22caa573..0222ac4a 100644 --- a/src/net/netlink.c +++ b/src/net/netlink.c @@ -423,7 +423,8 @@ int ds_nl_set_master(ds_nl_ctx_t *ctx, const char *ifname, const char *master) { * Bring link UP / DOWN * ---------------------------------------------------------------------------*/ -int ds_nl_link_up(ds_nl_ctx_t *ctx, const char *ifname) { +/* Set or clear IFF_UP on an interface (shared by link_up / link_down). */ +static int ds_nl_link_set_up(ds_nl_ctx_t *ctx, const char *ifname, int up) { int idx = ds_nl_get_ifindex(ctx, ifname); if (idx <= 0) return -ENODEV; @@ -438,29 +439,17 @@ int ds_nl_link_up(ds_nl_ctx_t *ctx, const char *ifname) { req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.i.ifi_family = AF_UNSPEC; req.i.ifi_index = idx; - req.i.ifi_flags = IFF_UP; + req.i.ifi_flags = up ? IFF_UP : 0; req.i.ifi_change = IFF_UP; return ds_nl_talk(ctx, &req.n); } -int ds_nl_link_down(ds_nl_ctx_t *ctx, const char *ifname) { - int idx = ds_nl_get_ifindex(ctx, ifname); - if (idx <= 0) - return -ENODEV; +int ds_nl_link_up(ds_nl_ctx_t *ctx, const char *ifname) { + return ds_nl_link_set_up(ctx, ifname, 1); +} - struct { - struct nlmsghdr n; - struct ifinfomsg i; - } req; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_type = RTM_NEWLINK; - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - req.i.ifi_family = AF_UNSPEC; - req.i.ifi_index = idx; - req.i.ifi_flags = 0; - req.i.ifi_change = IFF_UP; - return ds_nl_talk(ctx, &req.n); +int ds_nl_link_down(ds_nl_ctx_t *ctx, const char *ifname) { + return ds_nl_link_set_up(ctx, ifname, 0); } /* --------------------------------------------------------------------------- diff --git a/src/net/network.c b/src/net/network.c index cfbbc50a..5b975bf2 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -79,34 +79,25 @@ static uint32_t ds_net_hash_string(const char *s) { return h; } -/* Derive a stable, locally-administered unicast MAC from the container name. - * The same name always yields the same address, so a gateway (e.g. OpenWrt) - * sees one persistent host across restarts instead of a fresh random MAC - - * and therefore one DHCP lease / LuCI entry - every boot. */ -static void ds_container_mac(const char *name, uint8_t mac[6]) { - uint32_t h1 = ds_net_hash_string(name); - char salted[300]; - snprintf(salted, sizeof(salted), "ds-mac:%s", name ? name : ""); - uint32_t h2 = ds_net_hash_string(salted); - mac[0] = 0x02; /* locally administered (bit1), unicast (bit0 clear) */ - mac[1] = (uint8_t)(h1 >> 24); - mac[2] = (uint8_t)(h1 >> 16); - mac[3] = (uint8_t)(h1 >> 8); - mac[4] = (uint8_t)(h1); - mac[5] = (uint8_t)(h2); -} - -/* Derive a stable MAC for a gateway LAN-side veth from its segment key - * ("{gateway}:{net}"). The gateway's LAN interface (e.g. eth1 inside OpenWrt) - * then keeps the same MAC every time the cable is (re)plugged - across gateway - * reboots and self-heal re-wiring - so netifd sees one persistent device - * instead of re-initialising a new random-MAC device each time. */ -static void ds_segment_mac(const char *key, uint8_t mac[6]) { +/* Derive a stable, locally-administered unicast MAC from a key string, salted + * with a domain prefix so the two callers never collide on the same key. + * + * "ds-mac:" - the container's own eth0. A gateway (e.g. + * OpenWrt) then sees one persistent host + * across restarts - one DHCP lease / LuCI + * entry - instead of a fresh random MAC. + * "ds-gwmac:" - a gateway LAN-side veth (becomes e.g. eth1 + * inside OpenWrt). Keeps the same MAC across + * every (re)plug so netifd sees one + * persistent device, not a new one each time. + */ +static void ds_derive_mac(const char *key, const char *salt_prefix, + uint8_t mac[6]) { uint32_t h1 = ds_net_hash_string(key); - char salted[400]; - snprintf(salted, sizeof(salted), "ds-gwmac:%s", key ? key : ""); + char salted[512]; + snprintf(salted, sizeof(salted), "%s%s", salt_prefix, key ? key : ""); uint32_t h2 = ds_net_hash_string(salted); - mac[0] = 0x02; /* locally administered, unicast */ + mac[0] = 0x02; /* locally administered (bit1), unicast (bit0 clear) */ mac[1] = (uint8_t)(h1 >> 24); mac[2] = (uint8_t)(h1 >> 16); mac[3] = (uint8_t)(h1 >> 8); @@ -456,9 +447,7 @@ int ds_net_check_ip_collision(const char *ip_str, const char *exclude_name) { * collision. Deterministic on first boot → same row every time the same * container name is used, spreading containers across the /16. */ static void ds_net_auto_assign_ip(struct ds_config *cfg) { - uint32_t hash = 5381; - for (const char *p = cfg->container_name; *p; p++) - hash = ((hash << 5) + hash) ^ (unsigned char)*p; + uint32_t hash = ds_net_hash_string(cfg->container_name); int o3 = (int)((hash >> 8) % 254) + 1; /* 1-254 */ int o4 = (int)(hash % 254) + 1; /* 1-254 */ @@ -1001,7 +990,7 @@ static int gateway_ensure_lan_uplink_locked(struct ds_config *cfg, char key[384]; uint8_t mac[6]; gateway_hash_key(cfg, key, sizeof(key)); - ds_segment_mac(key, mac); + ds_derive_mac(key, "ds-gwmac:", mac); if (ds_nl_set_mac(ctx, gw_peer, mac) < 0) ds_warn("[NET] Gateway: failed to pin MAC on %s", gw_peer); } @@ -1104,7 +1093,7 @@ static int gateway_wire_client(struct ds_config *cfg, pid_t client_pid, * the move, so the gateway's DHCP leases see one host across reboots. */ { uint8_t mac[6]; - ds_container_mac(cfg->container_name, mac); + ds_derive_mac(cfg->container_name, "ds-mac:", mac); if (ds_nl_set_mac(ctx, app_peer, mac) < 0) ds_warn("[NET] Gateway: failed to pin MAC on %s", app_peer); } @@ -1289,7 +1278,7 @@ int setup_veth_child_side_named(struct ds_config *cfg, const char *peer_name, * churn) instead of a new random MAC each boot. Set while down, pre-up. */ if (cfg && cfg->container_name[0]) { uint8_t mac[6]; - ds_container_mac(cfg->container_name, mac); + ds_derive_mac(cfg->container_name, "ds-mac:", mac); if (ds_nl_set_mac(ctx, "eth0", mac) < 0) ds_warn("[NET] Child: failed to set deterministic MAC on eth0"); else From 2dfdf8945c9591b93b9f335b1d65936d9dd08fbd Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 13:00:09 +0530 Subject: [PATCH 11/25] net: log decoded target name instead of '' for standard verdicts Signed-off-by: ravindu644 --- src/net/iptables.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/net/iptables.c b/src/net/iptables.c index da4e9c7d..f1c87214 100644 --- a/src/net/iptables.c +++ b/src/net/iptables.c @@ -178,6 +178,17 @@ static int target_is_accept(const struct xt_entry_target *t) { return 0; } +/* Human-readable target name for logging. Standard targets (ACCEPT and the + * other built-in verdicts) carry an empty user.name - the verdict is encoded + * numerically - so decode the common ACCEPT case instead of printing ''. */ +static const char *target_label(const struct xt_entry_target *t) { + if (t->u.user.name[0]) + return t->u.user.name; + if (target_is_accept(t)) + return "ACCEPT"; + return "standard"; +} + /* --------------------------------------------------------------------------- * Internal: walk the blob to find an existing rule matching our fingerprint. * @@ -543,7 +554,8 @@ static int remove_matching_rules(int fd, const char *table_name, ei++; continue; } - ds_log("[IPT] remove: dropping '%s' rule at offset %u", tname, offset); + ds_log("[IPT] remove: dropping '%s' rule at offset %u", target_label(t), + offset); cumulative_gone += e->next_offset; removed_count++; } else { From e876f99e6b5ddb3c46ccbfcb10ae678e34520d80 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 13:28:36 +0530 Subject: [PATCH 12/25] net: fix DHCP source MAC for bridgeless NAT; harden gateway on no-bridge kernels Signed-off-by: ravindu644 --- src/net/dhcp.c | 13 ++++++++----- src/net/network.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/net/dhcp.c b/src/net/dhcp.c index f101b555..ba13ef56 100644 --- a/src/net/dhcp.c +++ b/src/net/dhcp.c @@ -555,21 +555,24 @@ void ds_dhcp_server_start(struct ds_config *cfg, const char *veth_host, g_dhcp.offer_ip_be = offer_ip_be; g_dhcp.gw_ip_be = gw_ip_be; - /* Fetch Bridge MAC */ - /* We need the bridge MAC to spoof the source in DHCP replies. - * If we use 00:00:00... or a random MAC, the container's ARP will break. */ + /* Source MAC for DHCP replies = the MAC of the interface we transmit on + * (veth_host, the bind interface). That device egresses the reply frame, + * and in bridgeless mode it also owns the gateway IP, so the container's ARP + * for the gateway resolves to a real MAC. Looking up the bind interface + * works in both bridged and bridgeless modes - no hardcoded bridge + * dependency. Falling back to all-zeros would break the container's ARP. */ int s = socket(AF_INET, SOCK_DGRAM, 0); if (s >= 0) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); - safe_strncpy(ifr.ifr_name, DS_NAT_BRIDGE, IFNAMSIZ); + safe_strncpy(ifr.ifr_name, veth_host, IFNAMSIZ); if (ioctl(s, SIOCGIFHWADDR, &ifr) == 0) { memcpy(g_dhcp.server_mac, ifr.ifr_hwaddr.sa_data, 6); } else { /* Fallback to all-zeros if SIOCGIFHWADDR fails (unlikely) */ memset(g_dhcp.server_mac, 0, 6); ds_warn("[DHCP] Failed to get MAC for %s: %s. Using all-zeros.", - DS_NAT_BRIDGE, strerror(errno)); + veth_host, strerror(errno)); } close(s); } else { diff --git a/src/net/network.c b/src/net/network.c index 5b975bf2..353c2bbc 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -952,8 +952,17 @@ static int gateway_ensure_lan_uplink_locked(struct ds_config *cfg, * authority on the delegated network. */ if (!ds_nl_link_exists(ctx, bridge)) { ds_log("[NET] Gateway: creating delegated LAN bridge %s", bridge); - if (ds_nl_create_bridge(ctx, bridge) < 0) { - ds_warn("[NET] Gateway: failed to create bridge %s", bridge); + int br = ds_nl_create_bridge(ctx, bridge); + if (br < 0) { + /* Bail before any veth/netns work. This should be unreachable - the + * startup capability probe (enforce_nat_safety) refuses gateway mode on + * a kernel without CONFIG_BRIDGE - but recognise EOPNOTSUPP explicitly + * so we never cascade into further unsupported operations. */ + if (br == -EOPNOTSUPP) + ds_warn("[NET] Gateway: kernel lacks CONFIG_BRIDGE - cannot wire " + "delegated LAN (gateway mode requires bridge support)"); + else + ds_warn("[NET] Gateway: failed to create bridge %s", bridge); ds_nl_close(ctx); return -1; } From 06b1378e14717cefe5cd26bb28caecd28ebe7215 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 14:09:08 +0530 Subject: [PATCH 13/25] app: fix Panel tab polling not resuming after returning from background Signed-off-by: ravindu644 --- .../app/ui/screen/ControlPanelScreen.kt | 24 ++-- .../app/ui/viewmodel/SystemStatsViewModel.kt | 132 +++++++----------- 2 files changed, 68 insertions(+), 88 deletions(-) diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt index d308eef4..5ee5b062 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt @@ -13,6 +13,9 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle import com.droidspaces.app.ui.component.EmptyState import com.droidspaces.app.ui.component.ErrorState import com.droidspaces.app.ui.component.RootUnavailableState @@ -46,18 +49,23 @@ fun ControlPanelScreen( // Get running containers - derived from ViewModel state val runningContainers = containerViewModel.containerList.filter { it.isRunning } - // Start system stats monitoring (only once per screen lifetime) - // Synchronized with DisposableEffect to ensure polling stops when navigating away - DisposableEffect(Unit) { - systemStatsViewModel.startMonitoring() - onDispose { - systemStatsViewModel.stopMonitoring() + val lifecycleOwner = LocalLifecycleOwner.current + + // Poll only while this screen is composed (i.e. the Panel tab is selected) + // AND the app is in the foreground (Lifecycle STARTED). repeatOnLifecycle + // cancels the loop on background / tab-away and restarts it on return, so + // re-opening the app on the Panel tab resumes polling without a tab switch. + LaunchedEffect(Unit) { + lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + systemStatsViewModel.monitorSystem() } } - // Start container monitoring loop; restarts if running container list changes + // Container loop restarts whenever the running container set changes. LaunchedEffect(runningContainers) { - systemStatsViewModel.startContainerMonitoring(runningContainers) + lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { + systemStatsViewModel.monitorContainers(runningContainers) + } } val containerUsageMap = systemStatsViewModel.containerUsageMap diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt index 07730894..a27c5ced 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt @@ -7,39 +7,24 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateMapOf import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.viewModelScope -import androidx.lifecycle.ProcessLifecycleOwner -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver import com.droidspaces.app.util.AndroidSystemStatsCollector import com.droidspaces.app.util.ContainerInfo import com.droidspaces.app.util.ContainerOSInfoManager import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.delay -import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +/** + * Holds host + per-container stats and exposes the polling loops as suspend + * functions. The loops are NOT self-managed here: the screen drives them via + * repeatOnLifecycle(STARTED), so polling runs only while the Panel tab is + * actually on screen AND the app is in the foreground, and is cancelled + * structurally when either stops being true. This avoids the old + * ProcessLifecycleOwner observer, which stopped on background but never + * restarted on return (polling stayed dead until a tab switch re-composed it). + */ class SystemStatsViewModel(application: Application) : AndroidViewModel(application) { - private var isAppInForeground = true - private val lifecycleObserver = LifecycleEventObserver { _, event -> - when (event) { - Lifecycle.Event.ON_START -> { - isAppInForeground = true - } - Lifecycle.Event.ON_STOP -> { - isAppInForeground = false - stopMonitoring() // Shutdown polling when app backgrounded - } - else -> {} - } - } - - init { - // Observe app-level lifecycle to stop polling in background - ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleObserver) - } - companion object { private const val TAG = "SystemStatsViewModel" private const val SYSTEM_INTERVAL_MS = 2000L @@ -53,81 +38,68 @@ class SystemStatsViewModel(application: Application) : AndroidViewModel(applicat var containerUsageMap = mutableStateMapOf() private set - private var systemJob: Job? = null - private var containerJob: Job? = null - - fun startMonitoring() { - if (!isAppInForeground) return - systemJob?.cancel() - systemJob = viewModelScope.launch(Dispatchers.IO) { - while (true) { - try { - systemUsage = AndroidSystemStatsCollector.collectUsage() - } catch (e: Exception) { - Log.e(TAG, "Failed to collect system usage", e) + /** + * Poll host system usage every [SYSTEM_INTERVAL_MS] until the caller's + * coroutine is cancelled (e.g. the screen leaves STARTED). + */ + suspend fun monitorSystem() { + while (true) { + try { + systemUsage = withContext(Dispatchers.IO) { + AndroidSystemStatsCollector.collectUsage() } - delay(SYSTEM_INTERVAL_MS) + } catch (e: Exception) { + Log.e(TAG, "Failed to collect system usage", e) } + delay(SYSTEM_INTERVAL_MS) } } - fun startContainerMonitoring(containers: List) { - if (!isAppInForeground) return - containerJob?.cancel() + /** + * Poll OS info for every running container until cancelled. Returns + * immediately when nothing is running; the caller re-invokes with a fresh + * list whenever the running set changes. + */ + suspend fun monitorContainers(containers: List) { val running = containers.filter { it.isRunning } if (running.isEmpty()) return - containerJob = viewModelScope.launch(Dispatchers.IO) { - while (true) { - running.forEach { container -> - try { - val isAlive = com.droidspaces.app.util.ContainerManager + while (true) { + running.forEach { container -> + try { + val isAlive = withContext(Dispatchers.IO) { + com.droidspaces.app.util.ContainerManager .checkContainerStatus(container.name).first - if (!isAlive) { - // Kill all terminal sessions for this container - val ctx = getApplication() - ctx.startService( - android.content.Intent(ctx, com.droidspaces.app.service.TerminalSessionService::class.java).apply { - action = com.droidspaces.app.service.TerminalSessionService.ACTION_STOP_CONTAINER_SESSIONS - putExtra(com.droidspaces.app.service.TerminalSessionService.EXTRA_CONTAINER_NAME, container.name) - } - ) - containerUsageMap.remove(container.name) - return@forEach - } - val osInfo = ContainerOSInfoManager.getOSInfo( + } + if (!isAlive) { + // Kill all terminal sessions for this container + val ctx = getApplication() + ctx.startService( + android.content.Intent(ctx, com.droidspaces.app.service.TerminalSessionService::class.java).apply { + action = com.droidspaces.app.service.TerminalSessionService.ACTION_STOP_CONTAINER_SESSIONS + putExtra(com.droidspaces.app.service.TerminalSessionService.EXTRA_CONTAINER_NAME, container.name) + } + ) + containerUsageMap.remove(container.name) + return@forEach + } + val osInfo = withContext(Dispatchers.IO) { + ContainerOSInfoManager.getOSInfo( containerName = container.name, useCache = false, appContext = getApplication() ) - containerUsageMap[container.name] = osInfo - } catch (e: Exception) { - Log.e(TAG, "Failed to collect info for ${container.name}", e) } + containerUsageMap[container.name] = osInfo + } catch (e: Exception) { + Log.e(TAG, "Failed to collect info for ${container.name}", e) } - delay(CONTAINER_INTERVAL_MS) } + delay(CONTAINER_INTERVAL_MS) } } - fun stopContainerMonitoring() { - containerJob?.cancel() - containerJob = null - } - fun clearContainerUsage(containerName: String) { containerUsageMap.remove(containerName) } - - fun stopMonitoring() { - systemJob?.cancel() - systemJob = null - stopContainerMonitoring() - } - - override fun onCleared() { - super.onCleared() - ProcessLifecycleOwner.get().lifecycle.removeObserver(lifecycleObserver) - stopMonitoring() - } } From c7c629620acdc0a756187a413c9ef4349c955927 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 14:10:24 +0530 Subject: [PATCH 14/25] app: drop unused host systemUsage polling and its collector Signed-off-by: ravindu644 --- .../app/ui/screen/ControlPanelScreen.kt | 8 +- .../app/ui/viewmodel/SystemStatsViewModel.kt | 29 +---- .../app/util/AndroidSystemStatsCollector.kt | 101 ------------------ 3 files changed, 3 insertions(+), 135 deletions(-) delete mode 100644 Android/app/src/main/java/com/droidspaces/app/util/AndroidSystemStatsCollector.kt diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt index 5ee5b062..38dd32e0 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ControlPanelScreen.kt @@ -55,13 +55,7 @@ fun ControlPanelScreen( // AND the app is in the foreground (Lifecycle STARTED). repeatOnLifecycle // cancels the loop on background / tab-away and restarts it on return, so // re-opening the app on the Panel tab resumes polling without a tab switch. - LaunchedEffect(Unit) { - lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { - systemStatsViewModel.monitorSystem() - } - } - - // Container loop restarts whenever the running container set changes. + // Restarts whenever the running container set changes. LaunchedEffect(runningContainers) { lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { systemStatsViewModel.monitorContainers(runningContainers) diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt index a27c5ced..8ab04d8d 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/viewmodel/SystemStatsViewModel.kt @@ -2,12 +2,8 @@ package com.droidspaces.app.ui.viewmodel import android.app.Application import android.util.Log -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateMapOf import androidx.lifecycle.AndroidViewModel -import com.droidspaces.app.util.AndroidSystemStatsCollector import com.droidspaces.app.util.ContainerInfo import com.droidspaces.app.util.ContainerOSInfoManager import kotlinx.coroutines.Dispatchers @@ -15,8 +11,8 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.withContext /** - * Holds host + per-container stats and exposes the polling loops as suspend - * functions. The loops are NOT self-managed here: the screen drives them via + * Holds per-container stats and exposes the polling loop as a suspend function. + * The loop is NOT self-managed here: the screen drives it via * repeatOnLifecycle(STARTED), so polling runs only while the Panel tab is * actually on screen AND the app is in the foreground, and is cancelled * structurally when either stops being true. This avoids the old @@ -27,34 +23,13 @@ class SystemStatsViewModel(application: Application) : AndroidViewModel(applicat companion object { private const val TAG = "SystemStatsViewModel" - private const val SYSTEM_INTERVAL_MS = 2000L private const val CONTAINER_INTERVAL_MS = 2000L } - var systemUsage by mutableStateOf(AndroidSystemStatsCollector.SystemUsage()) - private set - // Per-container OS info (containerName -> OSInfo) — single source of truth for all UI var containerUsageMap = mutableStateMapOf() private set - /** - * Poll host system usage every [SYSTEM_INTERVAL_MS] until the caller's - * coroutine is cancelled (e.g. the screen leaves STARTED). - */ - suspend fun monitorSystem() { - while (true) { - try { - systemUsage = withContext(Dispatchers.IO) { - AndroidSystemStatsCollector.collectUsage() - } - } catch (e: Exception) { - Log.e(TAG, "Failed to collect system usage", e) - } - delay(SYSTEM_INTERVAL_MS) - } - } - /** * Poll OS info for every running container until cancelled. Returns * immediately when nothing is running; the caller re-invokes with a fresh diff --git a/Android/app/src/main/java/com/droidspaces/app/util/AndroidSystemStatsCollector.kt b/Android/app/src/main/java/com/droidspaces/app/util/AndroidSystemStatsCollector.kt deleted file mode 100644 index 0acd638c..00000000 --- a/Android/app/src/main/java/com/droidspaces/app/util/AndroidSystemStatsCollector.kt +++ /dev/null @@ -1,101 +0,0 @@ -package com.droidspaces.app.util - -import android.util.Log -import com.topjohnwu.superuser.Shell -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -/** Collects real-time Android system statistics from /proc on the host. */ -object AndroidSystemStatsCollector { - private const val TAG = "AndroidSystemStatsCollector" - - data class SystemUsage( - val cpuPercent: Double = 0.0, - val ramPercent: Double = 0.0, - val activeRamKb: Long = 0, - val totalRamKb: Long = 0, - val temperature: String = "N/A" - ) - - private var prevCpuTotal = 0L - private var prevCpuIdle = 0L - - suspend fun collectUsage(): SystemUsage = withContext(Dispatchers.IO) { - try { - val (ramPercent, activeRam, totalRam) = getDetailedRamUsage() - val cpuPercent = getCpuUsage() - val temperature = getTemperature() - SystemUsage(cpuPercent, ramPercent, activeRam, totalRam, temperature) - } catch (e: Exception) { - Log.e(TAG, "Failed to collect system usage", e) - SystemUsage() - } - } - - private suspend fun getCpuUsage(): Double = withContext(Dispatchers.IO) { - try { - val result = Shell.cmd("cat /proc/stat | head -1").exec() - if (result.isSuccess && result.out.isNotEmpty()) { - val parts = result.out[0].trim().split("\\s+".toRegex()) - if (parts.size >= 8) { - val user = parts[1].toLongOrNull() ?: 0L - val nice = parts[2].toLongOrNull() ?: 0L - val system = parts[3].toLongOrNull() ?: 0L - val idle = parts[4].toLongOrNull() ?: 0L - val iowait = parts[5].toLongOrNull() ?: 0L - val total = user + nice + system + idle + iowait - if (prevCpuTotal > 0 && total > prevCpuTotal) { - val totalDelta = total - prevCpuTotal - val idleDelta = idle - prevCpuIdle - val percent = ((totalDelta - idleDelta).toDouble() / totalDelta * 100.0) - .coerceIn(0.0, 100.0) - prevCpuTotal = total; prevCpuIdle = idle - return@withContext percent - } - prevCpuTotal = total; prevCpuIdle = idle - } - } - } catch (e: Exception) { Log.e(TAG, "Error getting CPU usage", e) } - 0.0 - } - - private suspend fun getDetailedRamUsage(): Triple = withContext(Dispatchers.IO) { - try { - val result = Shell.cmd("cat /proc/meminfo | grep -E 'MemTotal|MemAvailable'").exec() - if (result.isSuccess && result.out.size >= 2) { - var memTotal = 0L; var memAvailable = 0L - result.out.forEach { line -> - val parts = line.trim().split("\\s+".toRegex()) - if (parts.size >= 2) when { - line.contains("MemTotal") -> memTotal = parts[1].toLongOrNull() ?: 0L - line.contains("MemAvailable") -> memAvailable = parts[1].toLongOrNull() ?: 0L - } - } - if (memTotal > 0) { - val memUsed = memTotal - memAvailable - val percent = (memUsed.toDouble() / memTotal * 100.0).coerceIn(0.0, 100.0) - return@withContext Triple(percent, memUsed, memTotal) - } - } - } catch (e: Exception) { Log.e(TAG, "Error getting RAM usage", e) } - Triple(0.0, 0L, 0L) - } - - private suspend fun getTemperature(): String = withContext(Dispatchers.IO) { - val paths = listOf( - "/sys/class/thermal/thermal_zone0/temp", - "/sys/class/thermal/thermal_zone1/temp", - "/sys/devices/virtual/thermal/thermal_zone0/temp" - ) - for (path in paths) { - try { - val result = Shell.cmd("cat $path 2>/dev/null").exec() - if (result.isSuccess && result.out.isNotEmpty()) { - val mC = result.out[0].trim().toLongOrNull() - if (mC != null && mC > 0) return@withContext String.format("%.1f°C", mC / 1000.0) - } - } catch (_: Exception) {} - } - "N/A" - } -} From e50ebe86040aec0e6209c6ddbb14734d4140f07b Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 14:42:06 +0530 Subject: [PATCH 15/25] docs: document gateway mode, automatic uplink monitor, and --upstream pinning Signed-off-by: ravindu644 --- Documentation/Features.md | 39 ++++++++++++++--- Documentation/Linux-CLI.md | 35 +++++++++++++++- Documentation/Networking-From-Zero.md | 60 +++++++++++++++++++++++++++ Documentation/Usage-Android-App.md | 12 +++++- README.md | 2 +- 5 files changed, 140 insertions(+), 8 deletions(-) diff --git a/Documentation/Features.md b/Documentation/Features.md index 1dab0450..c48488e1 100644 --- a/Documentation/Features.md +++ b/Documentation/Features.md @@ -29,14 +29,16 @@ Linux namespaces are a kernel feature that partitions system resources so that e ### Network Namespace Isolation (`--net`) -Droidspaces supports three networking modes that determine whether a network namespace (`CLONE_NEWNET`) is used: +Droidspaces supports four networking modes that determine whether a network namespace (`CLONE_NEWNET`) is used: 1. **Host Mode (`--net=host`) - Default**: Droidspaces deliberately does **not** unshare the network namespace. The container shares the host's network stack. This greatly simplifies setup: containers get internet access immediately without virtual bridges, NAT, or firewall rules. On Android, where networking is already complex (cellular, Wi-Fi, VPN), this avoids a whole category of connectivity issues. -2. **NAT Mode (`--net=nat`)**: The container is placed in a private network namespace. It is connected to the host via a virtual bridge or veth pair, providing **Pure Network Isolation** while maintaining internet access through the host's active internet uplink, which is detected automatically. Compatible with the vast majority of Android devices. +2. **NAT Mode (`--net=nat`)**: The container is placed in a private network namespace. It is connected to the host via a virtual bridge or veth pair, providing **Pure Network Isolation** while maintaining internet access through the host's active internet uplink, which is detected automatically (or pinned manually with `--upstream`, see below). Compatible with the vast majority of Android devices. 3. **None Mode (`--net=none`)**: The container is placed in a private, air-gapped network namespace with only the loopback interface enabled for maximum security. +4. **Gateway Mode (`--net=gateway`)**: The container's LAN is delegated to *another* running container (typically OpenWRT). Droidspaces does only the L2 plumbing (bridge + veth pairs) and lets the gateway container own all policy - DHCP, DNS, firewall, routing, VPN. Ideal for VPN killswitches, segmented LANs, and traffic analysis. See the dedicated [Networking From Zero](Networking-From-Zero.md) guide for the full deep dive. + ### How It Compares to Chroot A `chroot` only changes the apparent root directory for a process. It provides no process isolation, no mount isolation, no hostname isolation, and no IPC isolation. Any process inside a chroot shares the host's PID space, can see and signal other processes, and cannot run an init system like systemd. @@ -249,9 +251,9 @@ Droidspaces validates bind mount targets with two protections: --- -## Network Isolation (3 Modes) +## Network Isolation (4 Modes) -Droidspaces provides three distinct networking modes to balance ease-of-use with advanced isolation. +Droidspaces provides four distinct networking modes to balance ease-of-use with advanced isolation. ### 1. Host Mode (`--net=host`) - Default The container shares the host's network namespace. @@ -272,6 +274,14 @@ The container is placed in a private network namespace (`CLONE_NEWNET`) and conn The container gets a private network namespace with only the loopback (`lo`) interface enabled. - **Use Case**: Maximum security for offline tasks. +### 4. Gateway Mode (`--net=gateway`) +The container is placed on an isolated L2 bridge whose **policy is owned by another running container** (typically OpenWRT) instead of by Droidspaces. Droidspaces does only the plumbing - it creates the bridge and the veth pairs and moves them into place; the gateway container provides DHCP, DNS, firewall, routing and VPN. +- **Required flag**: `--gateway=NAME` names the running container that acts as the router. +- **Segments**: `--gateway-net=NAME` (default `lan`) selects which bridge/segment the client lands on. Multiple clients sharing a `--gateway-net` share a LAN; different `--gateway-net` values are isolated segments through the same gateway. +- **Interface naming**: `--gateway-iface=IFACE` (default `eth1`) controls what the LAN interface is called *inside* the gateway container, so it matches the gateway's own config. +- **Self-healing**: wiring is driven entirely from the host side, so clients are (re)wired automatically when the gateway container starts or reboots - no client restart needed. +- **Use Cases**: VPN killswitch for selected containers, VLAN-style segmented LANs, single-chokepoint traffic analysis, gateway-wide DNS filtering. See [Networking From Zero](Networking-From-Zero.md) for the complete walkthrough. + ### Port Forwarding (NAT Mode) In NAT mode, you can expose container services to the host or local network using the `--port` flag. Supported formats: @@ -294,7 +304,26 @@ Forwarded ports are reachable from any network the host belongs to - including c ### Real-Time Uplink Monitoring -On Android, the connection often hops between Wi-Fi and Mobile Data. Droidspaces includes a **Route Monitor** that subscribes to kernel routing events (FIB rules, routes, links, addresses). The moment Android switches its default network (e.g., you walk out of Wi-Fi range), the monitor updates the kernel's policy routing to keep the container connected - no configuration, no restart. +On Android, the connection often hops between Wi-Fi and Mobile Data. Droidspaces includes a **Route Monitor** that subscribes to kernel routing events (FIB rules, routes, links, addresses). The moment Android switches its default network (e.g., you walk out of Wi-Fi range), the monitor updates the kernel's policy routing to keep the container connected - no configuration, no restart. The same monitor works on desktop Linux (e.g. a Wi-Fi to ethernet handoff), where it follows the main routing table's default route. + +### Manual Uplink Pinning (`--upstream`) +By default the uplink is fully automatic. When you want the container's WAN to **ignore the host's active network** and go out through a specific interface instead, pin it with `--upstream`. This switches auto-detection off entirely - the listed interface(s) become the *only* WAN candidates. + +```bash +# Single interface +--upstream=wlan0 + +# Priority-ordered list with wildcards (comma-separated) +--upstream=wlan0,rmnet* +``` + +- **Authoritative, not a fallback**: traffic never hops to whatever `netd` marks active - only to interfaces you listed. +- **Priority failover *within* the list**: the Route Monitor re-resolves on every link/route change and uses the first listed interface that is up and has internet. `wlan0,rmnet*` prefers Wi-Fi and falls back to mobile data, then back to Wi-Fi when it returns. +- **Literals and wildcards** (`*`, `?`): use `rmnet*` for mobile data, whose interface number is not stable across reconnects. +- **Disappear/reappear** mid-session is handled: no WAN until a pinned interface is up, then it wires automatically. +- **Use cases**: pin `tun0` to route the container exclusively through a phone-side VPN (a free killswitch), or pin `rmnet*` (with "Mobile data always active") to keep the container on cellular while the phone stays on Wi-Fi. + +> `--upstream` is only valid with `--net=nat`; it is ignored (with a warning) in other modes. --- diff --git a/Documentation/Linux-CLI.md b/Documentation/Linux-CLI.md index 79546692..20c3ef4d 100644 --- a/Documentation/Linux-CLI.md +++ b/Documentation/Linux-CLI.md @@ -110,11 +110,23 @@ sudo droidspaces --name=web,db,app stop | Option | Short | Description | |--------|-------|-------------| -| `--net=MODE` | | Networking mode: `host` (default), `nat`, or `none`. | +| `--net=MODE` | | Networking mode: `host` (default), `nat`, `none`, or `gateway`. | +| `--upstream=IFACE` | | Pin the NAT WAN to specific interface(s); disables automatic uplink detection. Comma-separated, priority-ordered, supports wildcards. Example: `--upstream=wlan0,rmnet*`. NAT mode only. | | `--port HOST:CONT[/proto]` | | Forward host port to container (NAT mode). Supports TCP/UDP. | | `--dns=SERVERS` | `-d` | Custom DNS servers, comma-separated. Example: `--dns=1.1.1.1,8.8.8.8` | | `--disable-ipv6` | | Disable IPv6 networking support (Host mode only). | +#### Gateway Mode + +Delegate a container's LAN to another running container (e.g. OpenWRT), which then owns DHCP, DNS, firewall and routing. Droidspaces only does the L2 plumbing. See [Networking From Zero](Networking-From-Zero.md) for the full guide. + +| Option | Short | Description | +|--------|-------|-------------| +| `--gateway=NAME` | | **Required** for `--net=gateway`. The running container that acts as the router. | +| `--gateway-net=NAME` | | LAN segment name / host bridge suffix (default: `lan`). Clients sharing a value share a LAN; different values are isolated segments. | +| `--gateway-iface=IFACE` | | Interface name as seen *inside* the gateway container (default: `eth1`). Each segment needs a unique name. | +| `--gateway-bridge=BR` | | Override the host bridge name (default: `ds-{gateway-net}`). | + ### Feature Flags | Option | Short | Description | @@ -240,6 +252,27 @@ sudo droidspaces \ start ``` +### NAT with a Pinned Uplink +Force the container's internet out through a specific interface instead of following the host's active network. Pin a VPN tunnel (`tun0`) as a killswitch, or `rmnet*` to stay on mobile data while the phone uses Wi-Fi: +```bash +sudo droidspaces \ + --name=vpnbox \ + --rootfs-img=/path/to/rootfs.img \ + --net=nat \ + --upstream=tun0 \ + start +``` + +### Gateway Mode (LAN owned by OpenWRT) +Start the router container first (in NAT mode), then attach clients to it: +```bash +# 1. the router +sudo droidspaces --name=openwrt --rootfs=/data/openwrt --net=nat start + +# 2. a client whose LAN/DHCP/firewall is owned by openwrt +sudo droidspaces --name=kali --rootfs=/data/kali --net=gateway --gateway=openwrt start +``` + ### Ephemeral Testing ```bash sudo droidspaces --name=test --rootfs=/path/to/rootfs --volatile start diff --git a/Documentation/Networking-From-Zero.md b/Documentation/Networking-From-Zero.md index 9e005ae3..05a6e2e6 100644 --- a/Documentation/Networking-From-Zero.md +++ b/Documentation/Networking-From-Zero.md @@ -23,6 +23,9 @@ keywords: droidspaces, networking, gateway, openwrt, nat, dhcp, dns, lan, wan, v - [Part 4: DNS (How Names Become Addresses)](#part-4-dns-how-names-become-addresses) - [Part 5: NAT (The Magic Your Router Does)](#part-5-nat-the-magic-your-router-does) - [NAT in Droidspaces](#nat-in-droidspaces) + - [How NAT mode picks the WAN uplink (automatic)](#how-nat-mode-picks-the-wan-uplink-automatic) + - [Pinning the uplink manually with --upstream](#pinning-the-uplink-manually-with---upstream) + - [Use cases for --upstream](#use-cases-for---upstream) - [Part 6: Bridges and Virtual Cables (Linux Plumbing)](#part-6-bridges-and-virtual-cables-linux-plumbing) - [What is a network bridge?](#what-is-a-network-bridge) - [What is a veth pair?](#what-is-a-veth-pair) @@ -240,6 +243,63 @@ In Droidspaces NAT mode, Droidspaces acts *exactly like your home router* - but - Droidspaces also runs an embedded DHCP server for the container and configures its DNS - On Android, a background route monitor detects the active internet uplink automatically (by reading the kernel's routing rules) and re-points container traffic the moment the active network changes (for example, Wi-Fi to mobile data handoff) +### How NAT mode picks the WAN uplink (automatic) + +A NAT container has to know *which* of Android's real interfaces currently has internet, so it can MASQUERADE through it. Phones make this hard: the active network hops between Wi-Fi, mobile data, USB-ethernet and VPN tunnels, and the interface names themselves are unstable (the mobile-data interface might be `rmnet0` one minute and `rmnet8` after a reconnect). + +By default Droidspaces handles all of this for you - **there is nothing to configure**: + +- It reads the kernel's *own* ground truth for "what is the internet interface right now." On Android that is the policy-routing rule `netd` installs for the active default network; on desktop Linux it is the main routing table's default route. +- A background **route monitor** subscribes to kernel routing events (rule, route, link and address changes). The instant the host switches networks - you walk out of Wi-Fi range and it falls back to mobile data, or you plug in a USB-ethernet dongle on a laptop - the monitor re-points the container's traffic. No restart, no config. +- CLAT/464xlat interfaces (the `v4-rmnet...` interfaces phones synthesise on IPv6-only mobile networks) are picked up automatically. + +This automatic mode is the right choice for the vast majority of users. The rest of this section is only relevant if you want to *override* it. + +### Pinning the uplink manually with `--upstream` + +Sometimes you do **not** want the container to follow whatever network the host is using. You want to force its internet out through one specific interface and keep it there. That is what `--upstream` does. + +When you pass `--upstream`, automatic detection is switched off entirely. The interface(s) you list become the *only* candidates the container will ever use for WAN - it never hops to whatever the host marks as its active default network. + +```bash +# Force the container's internet out through Wi-Fi, always +droidspaces --name=box --rootfs=/data/box --net=nat --upstream=wlan0 start +``` + +You can list **multiple interfaces, comma-separated**, and use **wildcards** (`*`, `?`): + +```bash +droidspaces --name=box --rootfs=/data/box --net=nat --upstream=wlan0,rmnet* start +``` + +The list is **priority-ordered**. The route monitor walks it top to bottom and uses the first interface that is currently up and actually has internet. So `wlan0,rmnet*` means "prefer Wi-Fi; if Wi-Fi is down, fall back to mobile data" - and when Wi-Fi returns, it switches back. The failover stays strictly *inside your list*; it never falls back to an interface you did not list. This is the key difference from auto mode - the WAN is yours to decide, not the host's. + +If a pinned interface is missing when the container starts, or disappears mid-session and later reappears, that is handled too: the container simply has no WAN until one of your pinned interfaces is up, then it wires up automatically. + +> **Why wildcards matter on mobile data:** Android does not give the mobile-data interface a stable number - it might be `rmnet0`, `rmnet8`, `rmnet_data2`, and the number can change across reconnects. Pinning a literal `rmnet0` will break the next time it comes up as something else. Pin `rmnet*` instead and it keeps working. + +### Use cases for `--upstream` + +**1. Route the container's WAN through an Android VPN (`tun0`)** + +Connect a VPN on the phone itself - ProtonVPN, WireGuard, OpenVPN, any app that creates a `tun0` interface. Then pin the container to it: + +```bash +droidspaces --name=box --rootfs=/data/box --net=nat --upstream=tun0 start +``` + +Now all of the container's traffic goes out through the VPN tunnel, and *only* the tunnel. If the VPN drops, `tun0` disappears and the container loses internet instead of leaking out over your real connection - a simple killswitch, for free. + +**2. Container on mobile data while the phone stays on Wi-Fi** + +Android can keep the cellular radio up even while you are on Wi-Fi. Enable **"Mobile data always active"** in Developer Options, connect to Wi-Fi, then turn mobile data on. Both networks are now live at once. Pin the container to the mobile-data interface: + +```bash +droidspaces --name=box --rootfs=/data/box --net=nat --upstream=rmnet* start +``` + +The container's traffic goes out over mobile data while the rest of the phone keeps using Wi-Fi. Handy for testing from a different IP/network, putting a container's bandwidth onto cellular, or simply running something on a separate connection from everything else on the phone. + --- ## Part 6: Bridges and Virtual Cables (Linux Plumbing) diff --git a/Documentation/Usage-Android-App.md b/Documentation/Usage-Android-App.md index 95de8979..acf707ab 100644 --- a/Documentation/Usage-Android-App.md +++ b/Documentation/Usage-Android-App.md @@ -68,15 +68,25 @@ The repository supports third-party rootfs sources in the same JSON format. ## Networking Configuration -When editing or creating a container, you can choose from three networking modes: +When editing or creating a container, you can choose from four networking modes: - **Host (Default)**: Shares host network directly. - **NAT (Isolated)**: Private network namespace with deterministic IP and port forwarding support. - **None**: No network access. +- **Gateway**: The container's LAN is delegated to another running container (typically OpenWRT), which owns DHCP, DNS, firewall and routing. Select the gateway container and (optionally) the LAN segment, interface and bridge in the **Gateway** settings. See [Networking From Zero](Networking-From-Zero.md) for the full guide. ### Internet Uplink (NAT Mode) If you select **NAT (Isolated)** mode, the internet uplink is detected fully automatically - there is nothing to configure. Droidspaces reads the kernel's own routing state to find the interface Android is currently using for internet (Wi-Fi, mobile data, ethernet) and a background Route Monitor keeps the container connected in real time as you switch networks. +#### Upstream Interface (Optional) +If you want the container to **ignore the active network** and pin its internet to specific interface(s), add them under **Upstream Interface**. This disables auto-detection and forces the WAN through your list only: + +- The list is **priority-ordered** and supports **wildcards** - e.g. `wlan0, rmnet*` prefers Wi-Fi and falls back to mobile data (use `rmnet*` because the mobile-data interface number is not stable). +- **Example - VPN killswitch**: run a VPN app on the phone and pin `tun0` so the container can only reach the internet through the tunnel. +- **Example - cellular while on Wi-Fi**: enable *Mobile data always active* in Developer Options, connect Wi-Fi, turn on mobile data, and pin `rmnet*` so the container uses cellular while the phone stays on Wi-Fi. + +Leave it empty to auto-detect the active uplink (the default, recommended for most users). + > [!NOTE] > NAT mode is IPv4 only. If your carrier only provides IPv6, see the [IPv4 NAT Workaround](Troubleshooting.md#ipv4-quirks). diff --git a/README.md b/README.md index 7eb0a623..957c0c43 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ The entire runtime is a **single static binary** under 400KB, compiled against m | **Init System Support** | Run systemd, OpenRC or any other init system as PID 1. Full service management and proper boot/shutdown/reboot sequences. | | **Deep Android Integration** | Supports two daemon modes: **Native init.rc** (lowest-level integration with auto-spawn/unkillable persistence) and **Userspace Daemon** (app-togglable, starts via `post-fs-data.sh`, no image modification required). **Both modes bypass root-domain seccomp blocks to ensure stable container lifecycles** [[init.rc Developer Guide](./init/README.md)]. | | **Namespace Isolation** | Complete isolation via PID, MNT, UTS, IPC, and Cgroup namespaces. Each container has its own process tree, mount table, hostname, IPC resources, and cgroup hierarchy. | -| **Network Isolation** | **3 Networking Modes (Host, NAT, None)**. Pure network isolation via `CLONE_NEWNET` (NAT/None modes) or shared host networking (Host mode). Works on both Android and Linux. | +| **Network Isolation** | **4 Networking Modes (Host, NAT, None, Gateway)**. Pure network isolation via `CLONE_NEWNET` (NAT/None/Gateway modes) or shared host networking (Host mode). NAT auto-detects the active uplink (or pin it with `--upstream`); Gateway delegates LAN/DHCP/firewall to another container like OpenWRT. Works on both Android and Linux. | | **Android Display & GPU** | Three acceleration modes: **llvmpipe** (software, all devices), **VirGL** (Mali/PowerVR), and **Turnip** (native Qualcomm/Adreno). As of v6.3.0, the X server and VirGL server launch automatically when the container starts - zero manual Termux commands required. Environment variables (`DISPLAY=:5`, `GALLIUM_DRIVER=virpipe`) are injected automatically. [[More info](./Documentation/Graphics-and-Audio.md)] | | **Android Sound** | PulseAudio daemon runs on the host as the Termux user so Android's audio HAL grants it device access. The socket is bind-mounted into the container at `/tmp/.pulse-socket` and `PULSE_SERVER` is injected automatically - audio just works. [[More info](./Documentation/Graphics-and-Audio.md#pulseaudio)] | | **Linux GPU Acceleration** | Zero-configuration GPU acceleration for AMD and Intel GPUs on Linux desktop hosts. [[More info](./Documentation/Graphics-and-Audio.md)] | From c4129ebf1018259c6c3ee52debdbca4c107db0b7 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 14:43:11 +0530 Subject: [PATCH 16/25] docs: cover gateway mode and --upstream pinning in built-in help Signed-off-by: ravindu644 --- src/documentation.c | 48 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/src/documentation.c b/src/documentation.c index 9db66e2f..fc469a1f 100644 --- a/src/documentation.c +++ b/src/documentation.c @@ -283,20 +283,52 @@ static void print_page(int page, const char *bin) { printf("----------\n\n"); printf("%sIsolation Modes (--net):%s\n", bold, reset); - printf(" --net=host Shared with host (default)\n"); - printf(" --net=none No network access (air-gapped)\n"); - printf(" --net=nat Isolated namespace with internet access\n\n"); + printf(" --net=host Shared with host (default)\n"); + printf(" --net=none No network access (air-gapped)\n"); + printf(" --net=nat Isolated namespace with internet access\n"); + printf(" --net=gateway LAN delegated to another container " + "(e.g. OpenWRT)\n\n"); printf("%sNAT Mode Configuration:%s\n", bold, reset); printf(" %s --name=mycontainer --rootfs=/path/to/rootfs --net=nat " "start\n", bin); printf(" The internet uplink is detected automatically and tracked " - "in real time.\n"); - printf(" Use --upstream IFACE to pin WAN to a specific interface " - "(disables auto-detect),\n"); - printf(" e.g. --upstream wlan0 to route the container over Wi-Fi while " - "the phone uses mobile data.\n\n"); + "in real time\n"); + printf(" as the host switches networks (Wi-Fi <-> mobile data, " + "ethernet, etc.).\n\n"); + + printf("%sManual Uplink Pinning (--upstream, NAT only):%s\n", bold, reset); + printf(" Pin WAN to specific interface(s) and disable auto-detect. " + "The list is\n"); + printf(" comma-separated, priority-ordered, and supports wildcards.\n"); + printf(" --upstream=wlan0 Always use Wi-Fi\n"); + printf(" --upstream=wlan0,rmnet* Prefer Wi-Fi, fall back to mobile " + "data\n"); + printf(" --upstream=tun0 Route only through a phone VPN " + "(killswitch)\n"); + printf(" --upstream=rmnet* Stay on mobile data while the phone " + "uses Wi-Fi\n"); + printf(" (Use rmnet* - the mobile-data interface number is not stable " + "across reconnects.)\n\n"); + + printf("%sGateway Mode Configuration:%s\n", bold, reset); + printf(" Delegate the LAN to another running container (e.g. OpenWRT), " + "which owns\n"); + printf(" DHCP, DNS, firewall and routing. Start the gateway first, " + "then the client.\n"); + printf(" %s --name=openwrt --rootfs=/path/to/openwrt --net=nat start\n", + bin); + printf(" %s --name=kali --rootfs=/path/to/kali --net=gateway " + "--gateway=openwrt start\n", + bin); + printf(" --gateway=NAME Gateway container (required)\n"); + printf(" --gateway-net=NAME LAN segment / bridge suffix " + "(default: lan)\n"); + printf(" --gateway-iface=IFACE Interface name inside the gateway " + "(default: eth1)\n"); + printf(" --gateway-bridge=BR Override host bridge name " + "(default: ds-NAME)\n\n"); printf("%sPort Forwarding (NAT only):%s\n", bold, reset); printf(" --port=8080:80 Single port\n"); From d9e6938062bcdf52b2a7f638967a8c8c22a57994 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 14:55:04 +0530 Subject: [PATCH 17/25] docs: link Networking From Zero guide in README Signed-off-by: ravindu644 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 957c0c43..adff5872 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,7 @@ For GPU acceleration methods, sound setup, DE auto-boot internals, and Linux des | Document | Description | |----------|-------------| | [Feature Deep Dives](Documentation/Features.md) | Detailed explanation of each major feature. | +| [Networking From Zero](Documentation/Networking-From-Zero.md) | Beginner-friendly guide to every networking concept behind Droidspaces - NAT, automatic uplink detection, `--upstream` pinning, and gateway mode with OpenWRT. | | [Display, Audio & Desktop Guide](Documentation/Graphics-and-Audio.md) | GPU acceleration, PulseAudio sound, and desktop environment auto-boot on Android and Linux. | | [Cool Things You Can Do (Tailscale, Docker, etc.)](Documentation/Cool-things-you-can-do.md) | Practical recipes for running Tailscale, Docker, and other tools inside containers. | | [Uninstallation Guide](Documentation/Uninstallation.md) | How to remove Droidspaces from your system. | From 9e738a83942d7cf4d16be6ccdd4799e83507489b Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 16:11:28 +0530 Subject: [PATCH 18/25] net: heal stale gateway cable when its peer outlives the gateway netns Signed-off-by: ravindu644 --- src/net/network.c | 80 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/src/net/network.c b/src/net/network.c index 353c2bbc..0cfb2d34 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -208,6 +208,42 @@ static int ds_netns_rename_up(const char *netns_path, const char *old_name, return ret; } +/* Return 1 if interface `ifname` exists inside the netns at `netns_path`, else + * 0. Used to tell a healthy gateway cable (its peer really lives inside the + * CURRENT gateway netns) apart from a stale host-side veth whose peer is + * stranded in a zombie netns - one kept alive past container stop by a leftover + * process (e.g. tailscaled). On any error it returns 0, i.e. "not present", so + * the caller rebuilds the cable: the safe default. */ +static int netns_has_link(const char *netns_path, const char *ifname) { + if (!netns_path || !ifname || !ifname[0]) + return 0; + + int self_fd = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC); + if (self_fd < 0) + return 0; + int target_fd = open(netns_path, O_RDONLY | O_CLOEXEC); + if (target_fd < 0) { + close(self_fd); + return 0; + } + + int present = 0; + if (setns(target_fd, CLONE_NEWNET) == 0) { + ds_nl_ctx_t *ctx = ds_nl_open(); + if (ctx) { + present = ds_nl_link_exists(ctx, ifname) ? 1 : 0; + ds_nl_close(ctx); + } + if (setns(self_fd, CLONE_NEWNET) < 0) + ds_warn("[NET] Gateway: failed to restore netns after liveness check: %s", + strerror(errno)); + } + + close(target_fd); + close(self_fd); + return present; +} + /* --------------------------------------------------------------------------- * Uplink routing globals - shared by android routing setup and monitor * ---------------------------------------------------------------------------*/ @@ -918,10 +954,12 @@ static pid_t gateway_pid_of(const char *name) { * - ensure the gateway-side veth (ds-g) exists with its peer living in * the gateway netns as gw_if (e.g. eth1) * - * Idempotent: a live ds-g implies a live peer (veth pairs die together), - * so a repeat call is a cheap reattach. When the cable is absent we plug a - * fresh one into the gateway's (possibly just-rebooted) netns - this is what - * heals clients after a gateway restart, with no client restart. + * Idempotent: a repeat call is a cheap reattach when the cable is genuinely + * healthy (its peer lives inside the CURRENT gateway netns). When the cable is + * absent - or present but stale (peer stranded in a zombie netns that outlived + * the previous gateway) - we plug a fresh one into the gateway's (possibly + * just-rebooted) netns. This is what heals clients after a gateway restart, + * with no client restart. * * Returns 0 when the gateway-side cable is up, -1 on a netlink failure. * ---------------------------------------------------------------------------*/ @@ -972,19 +1010,33 @@ static int gateway_ensure_lan_uplink_locked(struct ds_config *cfg, write_file("/proc/sys/net/bridge/bridge-nf-call-iptables", "0"); write_file("/proc/sys/net/bridge/bridge-nf-call-ip6tables", "0"); - /* Cable already present → live gateway peer → just re-assert master + up. - * This is the idempotent no-op path when the segment is already healthy. */ - if (ds_nl_link_exists(ctx, gw_host)) { - if (ds_nl_set_master(ctx, gw_host, bridge) < 0) - ds_warn("[NET] Gateway: failed to reattach %s to %s", gw_host, bridge); - ds_nl_link_up(ctx, gw_host); - ds_nl_close(ctx); - return 0; - } - char gw_netns[PATH_MAX]; snprintf(gw_netns, sizeof(gw_netns), "/proc/%d/ns/net", (int)gw_pid); + /* Host-side cable present. This does NOT prove the peer is inside the + * CURRENT gateway netns: if a process kept the previous gateway's netns alive + * past `stop` (e.g. tailscaled), the veth pair survived and its peer is + * stranded there - so a stale ds-g can outlive the gateway it was built + * for. Verify gw_if actually exists inside this gateway before trusting the + * cable. + * - peer live in this netns → idempotent no-op: re-assert master + up. + * - peer absent → stale cable: delete it (which also reaps the + * stranded peer, veth pairs die together) and + * fall through to build a fresh one into this netns. */ + if (ds_nl_link_exists(ctx, gw_host)) { + if (netns_has_link(gw_netns, gw_if)) { + if (ds_nl_set_master(ctx, gw_host, bridge) < 0) + ds_warn("[NET] Gateway: failed to reattach %s to %s", gw_host, bridge); + ds_nl_link_up(ctx, gw_host); + ds_nl_close(ctx); + return 0; + } + ds_warn("[NET] Gateway: stale cable %s (peer not in gateway netns) - " + "rebuilding", + gw_host); + ds_nl_del_link(ctx, gw_host); + } + ds_log("[NET] Gateway: creating gateway veth %s <-> %s", gw_host, gw_peer); if (ds_nl_create_veth(ctx, gw_host, gw_peer) < 0) { ds_warn("[NET] Gateway: failed to create gateway veth pair"); From 8510a026494bea335b6b644e30d361512b717792 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Tue, 30 Jun 2026 17:07:38 +0530 Subject: [PATCH 19/25] net: explicitly reap gateway veth on gateway stop to free orphan netns Signed-off-by: ravindu644 --- src/include/droidspace.h | 5 ++ src/net/network.c | 111 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/include/droidspace.h b/src/include/droidspace.h index 66e75f30..f4937f60 100644 --- a/src/include/droidspace.h +++ b/src/include/droidspace.h @@ -695,6 +695,11 @@ void ds_net_start_route_monitor(void); * cable to every running client that delegates to it, with no client restart. * Called from the gateway container's monitor on each boot cycle. */ void ds_net_rewire_gateway_clients(const char *gateway_name, pid_t gateway_pid); +/* Gateway teardown: when a container that ACTS AS A GATEWAY stops, explicitly + * delete the gateway-side veth(s) it serves and reap any now-idle delegated + * bridge. The kernel does not auto-reap these (the host-side veth pins its + * orphan peer netns), so this prevents the leak. No-op for a non-gateway. */ +void ds_net_gateway_teardown(const char *gateway_name); int ds_net_disable_tx_checksum(const char *ifname); void parse_cidr(const char *cidr, uint32_t *ip_out, uint32_t *mask_out); diff --git a/src/net/network.c b/src/net/network.c index 0cfb2d34..7cdf05e1 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -1291,6 +1291,105 @@ void ds_net_rewire_gateway_clients(const char *gateway_name, closedir(d); } +/* --------------------------------------------------------------------------- + * ds_net_gateway_teardown + * + * Called when a container that ACTS AS A GATEWAY stops. The gateway-side veth + * ds-g lives in the host netns; its peer is the gateway's eth1. When the + * gateway stops the kernel does NOT auto-reap ds-g: the host-side veth itself + * pins its now-process-less peer netns (a veth end holds a reference to its + * peer's namespace), and that netns can only be freed by a cleanup_net that + * cannot run while ds-g pins it - a self-sustaining orphan. So we delete ds-g + * explicitly, exactly as NAT mode deletes ds-v. + * + * We do not track our own segments (clients choose --gateway-net), so scan the + * client configs that delegate to us, derive each segment's bridge + gateway + * veth, delete the veth (reaping the peer and freeing the netns), and reap the + * bridge once no client veths remain on it. Per-segment work runs under the + * same advisory lock client setup/cleanup use, and bridges are de-duplicated + * since many clients can share one segment. A no-op for a container that is + * nobody's gateway. + * ---------------------------------------------------------------------------*/ +void ds_net_gateway_teardown(const char *gateway_name) { + if (!gateway_name || !gateway_name[0]) + return; + + char containers_dir[PATH_MAX]; + snprintf(containers_dir, sizeof(containers_dir), "%s/Containers", + get_workspace_dir()); + DIR *d = opendir(containers_dir); + if (!d) + return; + + /* De-dupe segments: many clients can share one --gateway-net (one bridge). */ + char seen[32][IFNAMSIZ]; + int seen_count = 0; + + struct dirent *ent; + while ((ent = readdir(d)) != NULL) { + if (ent->d_name[0] == '.') + continue; + + struct ds_config c = {0}; + if (ds_config_load_by_name(ent->d_name, &c) != 0) + continue; + + if (!(c.net_mode == DS_NET_GATEWAY && c.gateway_container[0] && + strcmp(c.gateway_container, gateway_name) == 0)) { + ds_config_free(&c); + continue; + } + + char bridge[IFNAMSIZ], gw_host[IFNAMSIZ], gw_peer[IFNAMSIZ]; + gateway_bridge_name(&c, bridge, sizeof(bridge)); + gateway_veth_names(&c, gw_host, sizeof(gw_host), gw_peer, sizeof(gw_peer)); + + int dup = 0; + for (int i = 0; i < seen_count; i++) + if (strcmp(seen[i], bridge) == 0) { + dup = 1; + break; + } + if (dup) { + ds_config_free(&c); + continue; + } + if (seen_count < (int)(sizeof(seen) / sizeof(seen[0]))) + safe_strncpy(seen[seen_count++], bridge, IFNAMSIZ); + + ds_nl_ctx_t *ctx = ds_nl_open(); + if (!ctx) { + ds_config_free(&c); + continue; + } + + /* Same lock client setup/cleanup take, so we cannot race a concurrent + * client start/wire or the gateway's own rewire on the segment. */ + int lock = gateway_segment_lock(bridge); + + ds_nl_del_link(ctx, gw_host); + ds_log("[NET] Gateway teardown: removed gateway veth %s (segment %s)", + gw_host, bridge); + + int clients = ds_nl_count_bridge_members_with_prefix( + ctx, bridge, app_veth_host_prefix(&c)); + if (clients > 0) { + ds_log("[NET] Gateway teardown: %d client(s) still on %s - keeping " + "bridge", + clients, bridge); + } else { + ds_nl_del_link(ctx, bridge); + ds_log("[NET] Gateway teardown: reaped idle delegated LAN bridge %s", + bridge); + } + + gateway_segment_unlock(lock); + ds_nl_close(ctx); + ds_config_free(&c); + } + closedir(d); +} + /* --------------------------------------------------------------------------- * setup_veth_child_side_named * @@ -1999,6 +2098,12 @@ void ds_net_start_route_monitor(void) { * ---------------------------------------------------------------------------*/ void ds_net_cleanup(struct ds_config *cfg, pid_t container_pid) { + /* If this container is a gateway for others, explicitly tear down the + * gateway-side veth(s) it serves: the kernel will not auto-reap them (the + * host-side veth pins its orphan peer netns). No-op when nobody delegates + * to us, so it is safe to run for every stopping container. */ + ds_net_gateway_teardown(cfg->container_name); + if (cfg->net_mode == DS_NET_GATEWAY) { ds_nl_ctx_t *ctx = ds_nl_open(); if (!ctx) @@ -2037,8 +2142,10 @@ void ds_net_cleanup(struct ds_config *cfg, pid_t container_pid) { "- keeping bridge to avoid flapping its LAN iface", bridge, cfg->gateway_container); } else { - /* No clients and the gateway is gone (its netns death already took the - * gateway veth with its peer) - safe to reap the now-idle bridge. */ + /* No clients and the gateway is gone. The gateway's own stop already + * ran ds_net_gateway_teardown(), which explicitly deleted the gateway + * veth (the kernel does not auto-reap it), so the bridge is now idle + * and safe to reap. */ ds_nl_del_link(ctx, bridge); ds_log("[NET] Gateway cleanup: reaped idle delegated LAN bridge %s", bridge); From 39dbbdf793ee9dffba262cfdec086799ca32bd6e Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Wed, 1 Jul 2026 11:39:35 +0530 Subject: [PATCH 20/25] net: wire gateway clients before unblocking gateway init Move ds_net_rewire_gateway_clients() ahead of the DONE handshake write. The DONE write unblocks the container init to pivot_root and exec the real init (procd/netifd); plugging client LAN cables (eth1) after it hot-plugged them into a gateway whose netifd was already booting, racing its LAN bring-up. Wire the client cables first, then unblock, so the gateway execs its init with every client cable already present - mirroring how a client's eth0 is wired before its own DONE. Signed-off-by: ravindu644 --- src/monitor.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/monitor.c b/src/monitor.c index 49814b44..f79fca3c 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -401,6 +401,22 @@ reboot_loop:; } } + /* Gateway self-heal: if any running client delegates to THIS container as + * its gateway, (re)plug their LAN cable into our (possibly just-rebooted) + * netns now. Runs on every boot cycle - a cheap no-op when nobody routes + * through us - so a gateway reboot re-wires its clients with no client + * restart. + * + * This MUST run BEFORE the DONE handshake below. The DONE write is what + * unblocks init to proceed into pivot_root + exec of the real init + * (procd/netifd). A client's own eth0 is likewise wired before its DONE + * (setup_gateway_veth_side above); plugging the gateway's LAN cable(s) + * (eth1 ...) after DONE would hot-plug them into a gateway whose netifd + * is already booting, racing its LAN bring-up. Wire first, then unblock, + * so the gateway execs its init with every client cable already present. + */ + ds_net_rewire_gateway_clients(cfg->container_name, netns_pid); + /* Send handshake to init */ struct ds_net_handshake hs; ds_net_derive_handshake(netns_pid, cfg, &hs); @@ -413,13 +429,6 @@ reboot_loop:; if (write(cfg->net_done_pipe[1], &hs, sizeof(hs)) != (ssize_t)sizeof(hs)) ds_warn("[NET] Monitor: failed to write handshake to init"); close(cfg->net_done_pipe[1]); - - /* Gateway self-heal: if any running client delegates to THIS container as - * its gateway, (re)plug their LAN cable into our (possibly just-rebooted) - * netns now. Runs on every boot cycle - a cheap no-op when nobody routes - * through us - so a gateway reboot re-wires its clients with no client - * restart. */ - ds_net_rewire_gateway_clients(cfg->container_name, netns_pid); } } From 79570146f415cc18462800efa5e6af0cce7627c4 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Wed, 1 Jul 2026 11:53:13 +0530 Subject: [PATCH 21/25] mount: force image rootfs read-write before pivot_root Fixes OpenWRT external and internal reboot. On shutdown/reboot OpenWRT remounts its root read-only, leaving our mount point under /mnt/Droidspaces/ read-only too. External and internal reboots never unmount the rootfs.img (to keep restarts fast), so the next boot reuses that still-read-only mount and pivot_root fails to create .old_root ("Read-only file system") - the container never booted. Force the image mount read-write in internal_boot() right after the rootfs self-bind - the single point every boot path funnels through. Skipped for directory rootfs and volatile mode; no-op if already RW. Signed-off-by: ravindu644 --- src/boot.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/boot.c b/src/boot.c index 4abab540..5a26a917 100644 --- a/src/boot.c +++ b/src/boot.c @@ -215,6 +215,26 @@ int internal_boot(struct ds_config *cfg) { goto boot_fail; } + /* 4b. Force the image rootfs read-write - the single unified point covering + * fresh boot, restart, AND internal reboot. + * + * On shutdown/reboot OpenWRT remounts its root read-only, leaving our mount + * point under /mnt/Droidspaces/ read-only too. External and internal + * reboots never unmount the rootfs.img (to keep restarts fast), so the next + * boot reuses that still-read-only mount and pivot_root fails to create + * .old_root ("Read-only file system") - the container never boots. + * + * Skipped for directory rootfs (a fresh self-bind in this new namespace, its + * host backing fs already writable) and volatile mode (pivot_root targets the + * read-write overlay, not the read-only lower image). Safe: the guest synced + * the fs before flipping it read-only. A no-op when already read-write. */ + if (cfg->is_img_mount && !cfg->volatile_mode) { + if (mount(NULL, cfg->rootfs_path, NULL, + MS_REMOUNT | MS_NOATIME | MS_NODIRATIME, NULL) < 0) + ds_warn("Failed to remount rootfs %s read-write: %s", cfg->rootfs_path, + strerror(errno)); + } + /* 5. Set working directory to rootfs (required before pivot_root) */ if (chdir(cfg->rootfs_path) < 0) { ds_error("Failed to chdir to '%s': %s", cfg->rootfs_path, strerror(errno)); From 5f5c613125cb1d8bfc09b7e4b4fd79415ecee33a Mon Sep 17 00:00:00 2001 From: poqdavid Date: Wed, 1 Jul 2026 08:53:43 +0200 Subject: [PATCH 22/25] docs: Add Galaxy A15 4G (sma155f) to GKI support list (#225) --- Documentation/community-supported-devices.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/community-supported-devices.md b/Documentation/community-supported-devices.md index 4038b3d8..2aa28756 100644 --- a/Documentation/community-supported-devices.md +++ b/Documentation/community-supported-devices.md @@ -233,6 +233,7 @@ This document is a community-maintained compatibility list for Android devices k | **OnePlus ACE 6 Ultra** | PMB110 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_oneplus_mt6993/tree/oneplus/mt6993_b_16.0_ace_6_ultra) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 3 Pro** | OPD2513 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_3_pro) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | | **OnePlus Pad 4** | OPD2514 | Android16 (OOS/COS 16) | 6.12.58 | KernelSU Next + SusFS | [Source](https://github.com/OnePlusOSS/android_kernel_common_oneplus_sm8850/tree/oneplus/sm8850_b_16.0_pad_4) | [Download](https://github.com/WildKernels/OnePlus_KernelSU_SUSFS/releases) | Both | Turnip & Virgl | Working | [@fatalcoder524](https://github.com/fatalcoder524) | Check Latest Release Notes for more info and feature availability. Kernel versions can change for devices with active OTA support. | +| **Galaxy A15 4G** | SM-A155F | One UI 7.0 - Android 15| `5.10.226` | KernelSU/Next + SusFS | [Source](https://github.com/poqdavid/android_kernel_samsung_sma155f/tree/kernelsunext) | [Download](https://github.com/poqdavid/android_kernel_samsung_sma155f/releases) | Both | Virgl only | Working | [@poqdavid](https://github.com/poqdavid) | See the latest release notes for more details and feature availability. | ## Contribution guidelines To keep this list useful and reliable, please follow these rules when adding or updating entries: From ac346ff928536d0b4c36b4f0791500bc66122463 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Wed, 1 Jul 2026 12:36:24 +0530 Subject: [PATCH 23/25] ci: remove redundant run-name configuration from CI workflow Signed-off-by: ravindu644 --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40e48d4b..d7ed6693 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,4 @@ name: Droidspaces CI -run-name: ${{ github.event.head_commit.message || format('Release {0}', github.event.inputs.tag_name) || github.workflow }} on: push: From fe67da354204d8c1a91ec7d26759dec30873dfd5 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Wed, 1 Jul 2026 12:41:56 +0530 Subject: [PATCH 24/25] ci: name CI apk Droidspaces-universal-CI-.apk Use the short commit hash instead of the build date, and default the tag component to CI instead of test for non-release builds. Signed-off-by: ravindu644 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7ed6693..131a1fb6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,9 +104,9 @@ jobs: - name: Stage & Rename Artifacts run: | - TAG="${{ github.event.inputs.tag_name || 'test' }}" - DATE=$(date +%Y-%m-%d) - APK_NAME="Droidspaces-universal-${TAG}-${DATE}.apk" + TAG="${{ github.event.inputs.tag_name || 'CI' }}" + COMMIT_HASH=$(git log -1 --pretty=%h) + APK_NAME="Droidspaces-universal-${TAG}-${COMMIT_HASH}.apk" TAR_NAME=$(ls droidspaces-v*-*.tar.gz) mkdir -p dist mv Android/app/build/outputs/apk/release/app-release.apk dist/${APK_NAME} From 35c6dd4c2ea49fed8e54668a23f4148ea583bbb6 Mon Sep 17 00:00:00 2001 From: ravindu644 Date: Wed, 1 Jul 2026 13:11:14 +0530 Subject: [PATCH 25/25] build: name tarball with commit hash instead of date Match the CI apk naming: droidspaces-v-.tar.gz. Falls back to the date when not in a git checkout. Signed-off-by: ravindu644 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 00e6ed61..a92194d3 100644 --- a/Makefile +++ b/Makefile @@ -259,8 +259,8 @@ tarball: echo "[+] Created: $$TARBALL ($$(du -h $$TARBALL | cut -f1))" all-tarball: all-build - @DATE=$$(date +%Y-%m-%d); \ - TARBALL="$(BINARY_NAME)-v$(VERSION)-$$DATE.tar.gz"; \ + @COMMIT_HASH=$$(git rev-parse --short HEAD 2>/dev/null || date +%Y-%m-%d); \ + TARBALL="$(BINARY_NAME)-v$(VERSION)-$$COMMIT_HASH.tar.gz"; \ ROOT_DIR="$(BINARY_NAME)-v$(VERSION)"; \ TEMP_DIR="/tmp/droidspaces-tarball-$$$$"; \ mkdir -p $$TEMP_DIR/$$ROOT_DIR; \