Native under-display fingerprint (FOD) and Always-On Display (AOD) hardware compatibility layer for POCO X7 Pro (Rodin) running ColorOS ports.
The Rodin sensor wrapper also supports Rise to wake on ColorOS using Xiaomi pickup events while retaining the screen-off fingerprint hint. See sensor/README.md for the tested build and behavior.
Achieves full OEM-grade FOD unlock, instant optical highlight turn-off, zero lockscreen dimming, seamless animations, and AOD modes without patching ColorOS SystemUI bytecode and without requiring root / Magisk / KernelSU.
-
A real screen-off single tap restores the AOD clock and fingerprint hint when AOD is enabled and its schedule permits it. With AOD disabled, it shows the hint only; pickup does not force the clock on. See the single-tap integration guide.
-
Hardware FOD events are drained without blocking the sysfs fallback. Drivers without reliable notifications use an 8 ms fallback during active biometric sessions and a slower idle check. Authentication and the vendor's LHBM-ready synchronization remain unchanged.
-
The AOD daemon accepts ColorOS named and numeric wakefulness states, avoids panel overrides while interactive, and refreshes hint mode on native wake events after AOD settings change.
-
/system/bin/nees_aoddhas an explicitshell_execfile-context entry for its existingshellservice domain. Keep SELinux Enforcing. -
Double-tap to wake follows the ColorOS Settings toggle through Xiaomi's touch HAL. See the DT2W framework guide; Settings.apk remains unchanged.
-
Call proximity is a separate
oplus-services.jarfix. Use the proximity source patcher and guide; do not replace the sensor HAL to apply it.
See updating an existing ROM for builds, permanent installation, rollback and the test matrix. Other touchscreen/fingerprint pairings require their own hardware verification; the shared path does not establish equal speed on every sensor.
| Feature | Result |
|---|---|
| FOD | Under-display fingerprint unlock, including Goodix and Jiiov FOD sensors. |
| SOFOD | Fingerprint unlock while the display is off. |
| SOFOD hint | Fingerprint icon appears on the screen-off display when needed. |
| Rise to wake | A gentle lift wakes the lock screen and keeps the SOFOD hint working. |
| Front ALS & Auto-Brightness Stream | Bridges Xiaomi als_raw photodiode events to android.sensor.light and subtracts OLED panel optical leakage. |
| Jiiov idle FOD touch | After unlock, Jiiov FOD touch is disarmed on the screen-on launcher so stray presses do not illuminate LHBM; screen-off and new biometric sessions re-arm it. Goodix FOD behavior is unchanged. |
| AOD | All three ColorOS AOD modes work, including All day and Power saving; the vendor Doze overlay supplies the framework Doze service and light sensor resources. |
- ColorOS Display & Brightness Mapping (Coloros-display-autobrightness-fix-Rodin):
Provides the physical DisplayDeviceConfig XML (
display_id_4627039422300187648.xml), 2.0-nit night brightness floor adjustment (display_brightness_config_default.xml), and ColorOS lux-to-nit spline curves. Pairs with this repository's sensor HAL (sensors.mt6899.so) to deliver calibrated, instant auto-brightness without binary overwrite conflicts.
The Rise to wake fix is on current main; the earlier v4.0-working-final tag does not include it.
The Rodin AOD Doze overlay source and the installed APK are included for ROM baking. The current framework maps its two string resources; its config_dozeAfterScreenOff boolean is absent from this framework and has no effect.
ColorOS SystemUI / Keyguard / PowerManager
|
+----------------+----------------+
| |
v v
[librodin_fp_compat.so] [nees_aodd]
(Bionic DT_NEEDED in mfp-daemon) (Native Rust AOD Daemon)
| |
+-----------------+-----------------+ |
| | |
v v v
ColorOS AIDL Interfaces Xiaomi Hardware Path Display & Panel
* IBiometricsFingerprint * Goodix / FocalTech * Backlight control
* IDisplayPanelFeature TouchFeature HAL * Sysfs disp_feature
- Feature 211 (LHBM = 410) * /dev/disp_feature * SOFOD hint state
- Feature 217 (Smooth AOD) * /dev/input (FOD) * Zero-fork stream
- Feature 22 (HBM off) * Instant LHBM off
- The Bug: On stock ColorOS ports, when the user unlocked the phone and kept their thumb resting on the screen, the optical LHBM spotlight remained brightly lit until the finger was physically removed.
- The Root Cause: ColorOS requests HBM shutoff via
OPLUS_FEATURE_HBM_CONTROL(feature 22,value == 0). If the shim fails to reset Xiaomi touch mode 10 to0, the touchscreen firmware keeps the hardware LHBM spotlight active as long as physical touch is present. - The Solution:
- The millisecond authentication succeeds in
rodinBpOnAuthSucceeded,setTouchFeature(0, 10, 0)andconditionUpdate(4, 0)/(1, 0)are dispatched immediately. - In
OPLUS_FEATURE_HBM_CONTROLwhenvalue == 0, touch mode 10 is shut off instantly. persist.vendor.sys.fp.fod.lhbmoffafterresult=1is baked in so Xiaomi'smfp-daemonitself terminates LHBM immediately upon auth result.- The highlight extinguishes in 0 ms, identical to OEM HyperOS behavior.
- The millisecond authentication succeeds in
- Root Cause: SystemUI checks
KeyguardFeatureOption.isLocalHBM()by queryingvendor.oplus.hardware.displaypanelfeature.IDisplayPanelFeature/default. If this service is null, SystemUI assumes the panel does not support Local-HBM, turns onOnScreenFingerprintDimLayer(dimming the entire lockscreen), and falls back to an opaque black square behind the fingerprint icon. - The Solution:
librodin_fp_compat.soregisters the AIDL servicevendor.oplus.hardware.displaypanelfeature.IDisplayPanelFeature/defaultin ServiceManager.- Responds to Feature 211 (
OPLUS_FEATURE_UDFPS_TYPE) with0x410(OPLUS_UDFPS_LOCAL_HBM | OPLUS_UDFPS_LOCAL_HBM_ACCEL). - SystemUI receives
isLocalHBM = 410(true), completely destroyingOnScreenFingerprintDimLayer. The lockscreen remains at 100% full brightness and vibrant, with zero black box.
Rodin uses separate components for the touchscreen and optical fingerprint sensor. Goodix can name either component, so each unit should be described by its touch controller + FOD sensor pairing. Examples of Rodin hardware pairings are:
| Touch controller | FOD sensor |
|---|---|
| FocalTech | Goodix |
| FocalTech | Jiiov |
| Goodix | Goodix |
| Goodix | Jiiov |
- Dynamic Hardware Routing: Rather than writing to fixed sysfs nodes,
librodin_fp_compat.sobinds to Xiaomi's hardware abstraction layervendor.xiaomi.hw.touchfeature.ITouchFeature/default(Transaction 9, mode 10, value 1). Xiaomi's HAL automatically routes the FOD touch enable command to whichever touch IC is active. - Adaptive Edge Polling: Drivers like FocalTech do not always emit standard Linux input key events (
KEY_FOD_GESTURE_DOWN) or sysfs notifications. The compatibility worker polls both input device events and/sys/class/touch/touch_dev/fod_press_statuswith an adaptive 15–25ms active window to ensure instantaneous touch down/up detection on both Goodix and FocalTech hardware. - Jiiov FOD: A Rodin unit with Jiiov FOD confirmed the screen-on idle-touch fix. The compatibility layer checks
persist.vendor.sys.fp.vendor, disarms touch after Jiiov authentication while the display is on, and re-arms for screen-off or a new fingerprint operation. Goodix FOD follows the existing path; the touch controller can be Goodix or FocalTech.
- ColorOS
SmoothTransitionControllerqueries and sets panel feature217(OPLUS_FEATURE_AOD_SMOOTH). librodin_fp_compat.sointerceptsSET_FEATUREfor feature217and returnsSTATUS_OK(0). Seamless AOD, Classic AOD, and lockscreen fade-in animations render smoothly and stay lit indefinitely without the previous 2-second premature cutoff.
- When AOD is disabled or enters energy-saving hide (
DOZE->OFF),nees_aoddtogglesSetting_AodSwitchEnableto0. This informs ColorOSOnScreenFingerprintUiMechthat AOD is inactive, enabling the screen-off fingerprint icon to appear on pickup or screen tap (notifyWakeUpCallback type 1). - On touch or pickup callback,
nees_aoddimmediately ramps panel brightness to100for clear FOD icon visibility, dropping to0when the icon hides, and restoringSetting_AodSwitchEnable = 1when the screen wakes toON. - Rise to wake on ColorOS: The sensor wrapper maps Xiaomi pickup events to the tilt value expected by ColorOS's gesture service. It batches Xiaomi pickup before activation and leaves native FOD and AOD events untouched. No ColorOS app patch is required. The installed build passed three gentle lock-and-lift cycles with the SOFOD hint working.
nees_aoddoperates on pure in-memory string matching on the logcat stream with zero subprocess forks. Panel backlight is held at 28 duringDOZE_SUSPENDandperformAodUpdatewithout system overhead, preventing Android process watchdogs (MBrainServer) from killing the daemon.
- Using
patchelf --add-needed librodin_fp_compat.so /vendor/bin/hw/mfp-daemon, the shim is permanently baked into themfp-daemonbinary. - The Android bionic dynamic linker loads
librodin_fp_compat.soautomatically intomfp-daemonupon boot. NoLD_PRELOAD, Magisk, or root environment is needed. Clean-flashed devices boot with fully functional FOD out-of-the-box.
- Zero Permissive Domains: All
(typepermissive ...)directives are completely removed. - The entire ROM runs under global SELinux
Enforcing(getenforcereturnsEnforcing). - Full compliance with SafetyNet, Google Play Integrity, Google Wallet, and banking applications.
When porting or modifying system components, never switch to permissive mode. Follow this exact workflow to identify denials and add clean, versioned CIL rules:
Run via ADB:
# Check kernel audit buffer
adb shell "dmesg | grep avc"
# Check logcat audit events
adb shell "logcat -b all -d | grep -iE 'avc: denied'"Example denial message:
type=1400 audit(1790426908.016:38): avc: denied { read open getattr } for comm="mfp-daemon" path="/sys/devices/virtual/touch/touch_dev/fod_enable" dev="sysfs" ino=1234 scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=0
Break down the components:
scontext: Calling domain (hal_fingerprint_default)tcontext: Target object/domain (sysfs)tclass: Object class (file,dir,binder,service_manager,chr_file,property_service){ ... }: The denied action(s) (read,open,getattr,call,transfer,add,find,set)
In Treble-compliant vendor images (e.g. Android 14/15), system types referenced by vendor CIL files are versioned (e.g. _202404).
Check existing versioned symbols in your vendor image:
grep -E "\(type (sysfs_|system_server_|default_prop_)" /vendor/etc/selinux/vendor_sepolicy.cilConstruct the CIL allow rule:
(allow <scontext> <tcontext> (<tclass> (<actions...>)))Examples of verified strict rules:
; File and directory access
(allow hal_fingerprint_default sysfs_202404 (file (read open getattr)))
(allow hal_fingerprint_default sysfs_202404 (dir (search read open)))
; Binder IPC between HAL and system server
(allow hal_fingerprint_default system_server_202404 (binder (call transfer)))
(allow system_server_202404 hal_fingerprint_default (binder (call transfer)))
; Property reading
(allow hal_fingerprint_default default_prop_202404 (file (read open getattr map)))
(allow hal_fingerprint_default system_prop_202404 (file (read open getattr map)))When an AIDL service is added, servicemanager checks service_contexts.
- If you assign the service to an existing authorized type:
In
/vendor/etc/selinux/vendor_service_contexts:Becausevendor.oplus.hardware.displaypanelfeature.IDisplayPanelFeature/default u:object_r:vendor_hal_fingerprint_service_xiaomi:s0vendor_hal_fingerprint_service_xiaomiis already allowed to be added byhal_fingerprint_defaultand found byplatform_app_202404(SystemUI) andsystem_server_202404, registration succeeds with zero denials and zero extra CIL rules required.
Step 5: Critical Treble Step — Neutralize the 3 precompiled_sepolicy Files in /odm/etc/selinux & /vendor/etc/selinux
On modern Android Treble devices with dedicated vendor/odm partitions (like POCO X7 Pro / Rodin running ColorOS ports), Android ships up to 3 precompiled SELinux policy artifacts:
precompiled_sepolicyprecompiled_sepolicy.plat_sepolicy_and_mapping.sha256precompiled_sepolicy.*_sepolicy_and_mapping.sha256(e.g.system_extorproduct)
Why this is critical: During early boot, Android init verifies whether the SHA256 hashes of the system partitions match the stored .sha256 checksum files. If they match, init loads precompiled_sepolicy directly into the kernel and completely ignores your edits to vendor_sepolicy.cil and odm_sepolicy.cil! Any custom allow rules you added will never take effect.
The Professional Solution:
Remove or back up all 3 precompiled_sepolicy* files located in:
/odm/etc/selinux//vendor/etc/selinux/
When these 3 files are neutralized, Android init detects that no valid precompiled policy exists and automatically invokes /system/bin/secilc at boot time to compile plat_sepolicy.cil + vendor_sepolicy.cil + odm_sepolicy.cil into a monolithic runtime policy, seamlessly activating all custom strict rules with zero bootloop risk.
NEESS-COS-AOD-FOD-FIX/
├── bake_into_rom.sh # 1-command root ROM bake installer
├── README.md # Main documentation & SELinux guide
├── aod/ # Native Rust AOD helper daemon
│ ├── Cargo.toml
│ ├── Cargo.lock
│ ├── nees_aodd.rc # Init service definition (u:r:shell:s0)
│ └── src/main.rs # Zero-fork logcat listener & backlight manager
├── fod/ # Native C++ FOD & panel compatibility shim
│ ├── native/
│ │ ├── CMakeLists.txt
│ │ └── rodin_fp_compat.cpp # Instant LHBM off, Local-HBM 410, AIDL hooks
│ └── zz_rodin_fp_compat.rc # Hardware init & Goodix/Focaltech permissions
├── sepolicy/ # Pure strict Enforcing policies
│ ├── vendor_sepolicy.cil.append # Verified 100% strict enforcing CIL rules
│ ├── vendor_sepolicy_strict.cil.append # Standalone strict rules reference
│ ├── vendor_file_contexts.append # Vendor file contexts (erofs/ext4)
│ └── plat_file_contexts.append # Platform file contexts
├── system/ # Prepared system partition payloads
│ ├── bin/nees_aodd # Compiled native AOD daemon
│ ├── etc/init/nees_aodd.rc # AOD init script
│ └── build.prop.append # AOD & FOD system properties
├── vendor/ # Prepared vendor partition payloads
│ └── lib64/librodin_fp_compat.so # Compiled native FOD shim
└── scripts/ # Build & maintenance scripts
├── bake_into_rom.sh # Alternate script location
├── build_aod.sh # Cargo cross-compiler script
└── build_fod.sh # NDK CMake build script
chmod +x bake_into_rom.sh
./bake_into_rom.sh /path/to/unpacked_rom_rootThe script automatically:
- Copies
nees_aoddand its.rcintosystem/. - Copies
librodin_fp_compat.soandzz_rodin_fp_compat.rcintovendor/. - Patches
/vendor/bin/hw/mfp-daemonELF header withDT_NEEDED: librodin_fp_compat.so. - Injects strict CIL rules into
vendor_sepolicy.cil. - Maps
IDisplayPanelFeatureinvendor_service_contextsandodm_service_contexts. - Safely handles
precompiled_sepolicyto force fresh compile. - Updates
file_contextsforerofs/ext4image repackers. - Injects properties into
build.prop.
Run these commands in an ADB shell:
# 1. Verify global SELinux is 100% Enforcing
getenforce
# Output: Enforcing
# 2. Verify DisplayPanelFeature AIDL registration
service list | grep -i displaypanel
# Output: 522 vendor.oplus.hardware.displaypanelfeature.IDisplayPanelFeature/default: [...]
# 3. Verify SystemUI Local-HBM evaluation
logcat -d | grep -i "isLocalHBM"
# Output: FeatureOption-->isLocalHBM val=410
# 4. Verify ZERO SELinux denials for fingerprint & AOD
dmesg | grep -iE 'avc.*fingerprint'
# Output: (empty / zero denials)- NEESCHAL – Lead developer, hardware reverse engineering, protocol shims, and timing state machines.
- Community testers for feedback and telemetry logs.
Licensed under the Apache License, Version 2.0. Copyright (c) 2026 NEESCHAL-3 and NEESS-COS-AOD-FOD-FIX Contributors.