feat: Support HyperOS 4 (Android 17) - #183
Conversation
PR Summary by QodoSupport HyperOS 4 and Android 17 launcher gestures
AI Description
Diagram
High-Level Assessment
Files changed (29)
|
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed functional and compliance issues in the new native path (madvise guard idempotency and invoke failure handling) plus missing bundled Apache-2.0 license text referenced by the new native README.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adds Android 17 / HyperOS 4 support by introducing an LSPosed native payload to hook the HyperOS 4 launcher’s native gesture pipeline, and updates the system-server side hooks and user-facing docs/strings to reflect Android 9–17 support.
Changes:
- Add a new
native/CMake-built LSPosed entry (native_init) that inline/PLT hooks HyperOS 4 launcher native code paths to restore gesture-handle long press triggering. - Update system-server hook logic to safely gate/bypass ContextualSearch permission/provider checks only for MiCTS-managed invocations (and add a native-launcher trigger bridge).
- Bump documentation and localized strings from “Android 9–16” to “Android 9–17”, plus Gradle/packaging changes to build and ship the native library.
File summaries
| File | Description |
|---|---|
| README.md | Updates Chinese README support range to Android 9–17 and VIS notes. |
| README_en.md | Updates English README support range to Android 9–17. |
| README_ru.md | Updates Russian README support range to Android 9–17. |
| native/README.md | Documents the new HyperOS 4 native payload design and attribution. |
| native/native_api.h | Declares the native LSPosed API entry structure/types. |
| native/micts_native_hook.cpp | Implements launcher/runtime detection + inline hook routing to contextual search. |
| native/lsposed_hook_backend.h | Declares LSPosed hook backend helpers (PLT/inline + madvise guard). |
| native/lsposed_hook_backend.cpp | Implements PLT hooking, inline hooking wrapper, and MADV_DONTNEED guard logic. |
| native/launcher_cs_resolver.h | Declares resolver API + diagnostics for locating contextual-search functions. |
| native/launcher_cs_resolver.cpp | Implements ELF parsing + structural fingerprint resolver for target offsets. |
| native/exports-lsposed.map | Exports native_init symbol for LSPosed loading. |
| native/CMakeLists.txt | Adds arm64-only native build with hardening/linker flags and version script. |
| app/src/MiCTS/resources/META-INF/xposed/native_init.list | Registers the native entry library for LSPosed. |
| app/src/main/res/values/strings.xml | Updates module description to Android 9–17. |
| app/src/main/res/values-zh/strings.xml | Updates Chinese module description to Android 9–17. |
| app/src/main/res/values-zh-rTW/strings.xml | Updates zh-rTW module description to Android 9–17. |
| app/src/main/res/values-vi/strings.xml | Updates Vietnamese module description to Android 9–17. |
| app/src/main/res/values-tr/strings.xml | Updates Turkish module description to Android 9–17. |
| app/src/main/res/values-ru/strings.xml | Updates Russian module description to Android 9–17. |
| app/src/main/res/values-ja/strings.xml | Updates Japanese module description to Android 9–17. |
| app/src/main/res/values-es/strings.xml | Updates Spanish module description to Android 9–17. |
| app/src/main/res/values-el/strings.xml | Updates Greek module description to Android 9–17. |
| app/src/main/java/com/parallelc/micts/ModuleMain.kt | Wires in the new native launcher trigger hooker for Xiaomi on Android 17+. |
| app/src/main/java/com/parallelc/micts/hooker/NativeLauncherTriggerHooker.kt | Adds system-server hook to gate/bridge native launcher contextual-search requests. |
| app/src/main/java/com/parallelc/micts/hooker/LongPressHomeHooker.kt | Updates MIUI/HyperOS key-rule hooking to handle class split/overrides on HyperOS 4. |
| app/src/main/java/com/parallelc/micts/hooker/CSMSHooker.kt | Makes permission/provider bypass conditional via ThreadLocal and supports new overload. |
| app/build.gradle.kts | Adds NDK/CMake native build configuration and packaging adjustments. |
| .gitignore | Ignores .cxx build outputs. |
Review details
- Files reviewed: 26/28 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Bundle the Apache-2.0 licence text that native/README.md links to - Guard every image matching the runtime name instead of requiring a unique match, so an ambiguous basename no longer blocks hook installation - Fall back to the stock handler when the contextual-search invoke helper is unavailable, rather than consuming the gesture for nothing - Use a released NDK and CMake so CI can resolve them
Code Review by Qodo
1.
|
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces a substantial native hooking subsystem and build/packaging changes, and there are correctness concerns (e.g., concurrency in launcher-caller gating) that should be resolved and re-validated on target devices.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
app/src/main/java/com/parallelc/micts/hooker/NativeLauncherTriggerHooker.kt:89
isLauncherCallerreads/writeslauncherUidResolved/launcherUidwithout any synchronization. This can race across binder threads and lead to seeinglauncherUidResolved=truewith a stalelauncherUid, misclassifying callers and incorrectly bridging/consuming requests. Wrap the whole resolution + read path in a single synchronized block (or use atomics) so the state is published consistently.
private fun isLauncherCaller(uid: Int): Boolean {
if (launcherUidResolved) return uid == launcherUid
val context = runCatching {
Class.forName("android.app.ActivityThread")
.getDeclaredMethod("currentApplication")
app/src/main/java/com/parallelc/micts/hooker/LongPressHomeHooker.kt:40
- The thrown
NoSuchMethodExceptionmessage is misleading: the lookup falls back toonLongPress, but the exception always reports onlyonMiuiLongPress. This makes debugging OS variations harder when neither exists. Include both candidate method names in the error message.
val longPress = findCallback(rule, "onMiuiLongPress", "onLongPress")
?: throw NoSuchMethodException("${rule.name}.onMiuiLongPress")
module!!.hook(longPress).intercept(OnLongPressHooker())
app/build.gradle.kts:38
- The native payload build is configured in
defaultConfig, so it will be built/packaged for all flavors (includingVISTrigger). IfVISTriggerdoesn't loadMETA-INF/xposed/native_init.list, this adds build time and APK size without functional benefit. Consider scoping theexternalNativeBuild.cmake { targets/abiFilters }configuration to theMiCTSflavor (or excluding the .so from other variants).
externalNativeBuild {
cmake {
targets += "micts_hyos_lsp"
// The payload is arm64 only. Restrict the native build, not
// the APK — that would strip the dependencies' own libraries
- Files reviewed: 27/29 changed files
- Comments generated: 0 new
- Review effort level: Lite
A PLT slot already pointing at our replacement cannot be hooked again, so a failure partway through left the earlier hooks in place and made every later attempt fail on them — the feature probe would keep claiming contextual-search support with no routing behind it, until the process restarted. Skip whatever a previous attempt got through, and undo the feature override if the inline hook still cannot be installed.
|
Code review by qodo was updated up to the latest commit a20b236 |
The launcher's code is mapped straight out of the APK. When those pages are reclaimed they come back from the file, silently undoing the inline patch while LSPosed still holds a now-dangling trampoline — the process stays up, the payload stays loaded, nothing is logged, and the gesture simply stops working until the spawner is restarted. PLT hooks survive that because they patch the GOT rather than the code, so the motion-event hook is used as the checkpoint: it compares the handler against the prologue captured before patching, and on a match drops LSPosed's stale record before hooking again.
支持 HyperOS 4 (Android 17)
已在 Xiaomi 17 Pro OS 4.0.0.27 Beta A17 测试可用
Native 代码来源于 https://github.com/wxxsfxyzm/MiuiBackGestureHook