Using Infrared Camera for Face Recognition on Xiaomi 845 Series with Custom ROMs

Using Infrared Camera for Face Recognition on Xiaomi 845 Series with Custom ROMs

KaguraiYoRoy
06-03-2025 / 0 Comments / 162 Views / Checking if indexed by search engines...

Background

The Xiaomi 845 series, specifically the Mi 8 and Mi 8 Pro (UDFPS), feature a dedicated front-facing infrared camera for facial recognition. This enables facial unlock functionality even in complete darkness. However, when using a custom ROM like LineageOS compiled from its standard device tree, the infrared camera remains inaccessible, forcing the system to rely on the standard front camera. Interestingly, PixelExperience ROMs successfully utilize this hardware. This article explores the reasons behind this discrepancy and outlines the solution.

The Cause

CameraID

The first step is directing the face recognition module to use the infrared camera. Examining the PixelExperience device tree source code reveals an overlay that configures the face unlock service to use the camera with ID 5.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="override_front_cam_id">5</integer>
    <bool name="use_alternative_vendor_impl">true</bool>
</resources>

PixelExperience uses Motorola's face unlock solution. Many other custom ROMs, however, utilize AOSPA's ParanoidSense. Therefore, the PixelExperience overlay method isn't directly applicable.

Inspecting the ParanoidSense source code shows that it uses a system property, ro.face.sense_service.camera_id, to identify which camera to use.

    val cameraIdProp = SystemProperties.get("ro.face.sense_service.camera_id")

Thus, in theory, simply setting the ro.face.sense_service.camera_id property to 5 should direct it to the infrared camera.

The vendor.camera.aux.packagelist Property

Merely setting the CameraID property is insufficient; the face unlock module would simply fail to access the camera. Delving into the Android framework code reveals that the system, by default, hides auxiliary cameras (AuxCameras) beyond the primary front and rear cameras. The infrared camera falls into this AuxCamera category.

Using LineageOS framework code as an example:

    /**
     * Returns the number of physical cameras available on this device.
     * The return value of this method might change dynamically if the device
     * supports external cameras and an external camera is connected or
     * disconnected.
     *
     * If there is a
     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
     * logical multi-camera} in the system, to maintain app backward compatibility, this method will
     * only expose one camera per facing for all logical camera and physical camera groups.
     * Use camera2 API to see all cameras.
     *
     * @return total number of accessible camera devices, or 0 if there are no
     *   cameras or an error was encountered enumerating them.
     */
    public static int getNumberOfCameras() {
        int numberOfCameras = _getNumberOfCameras();
        if (!shouldExposeAuxCamera() && numberOfCameras > 2) {
            numberOfCameras = 2;
        }
        return numberOfCameras;
    }

As shown, even if a device has more than two cameras, if the shouldExposeAuxCamera() function returns False, the system reports only two cameras, preventing access to any camera with an ID greater than 1. Let's examine this function:

    /**
     * @hide
     */
    public static boolean shouldExposeAuxCamera() {
        /**
         * Force to expose only two cameras
         * if the package name does not falls in this bucket
         */
        String packageName = ActivityThread.currentOpPackageName();
        if (packageName == null)
            return true;
        List<String> packageList = Arrays.asList(
                SystemProperties.get("vendor.camera.aux.packagelist", packageName).split(","));
        List<String> packageExcludelist = Arrays.asList(
                SystemProperties.get("vendor.camera.aux.packageexcludelist", "").split(","));

        return packageList.contains(packageName) && !packageExcludelist.contains(packageName);
    }

The logic is clear: if the current application's package name is listed in the vendor.camera.aux.packagelist system property and is not in the vendor.camera.aux.packageexcludelist property, the function returns True, allowing access to auxiliary cameras.

The solution becomes evident: add the ParanoidSense package name (co.aospa.sense) to the vendor.camera.aux.packagelist property.

The Solution

Add the ParanoidSense package name co.aospa.sense to the vendor.camera.aux.packagelist property:

Set the ro.face.sense_service.camera_id property to specify the correct camera ID:

In the crDroid-modified version of ParanoidSense, which is placed in the system_ext partition (refer: https://gitlab.com/crdroidandroid/android_packages_apps_FaceUnlock/-/commit/545688260eb32ba19f348e84e3cae89ba29f20d1), this property should be added to the corresponding system_ext prop file.

1

Comments (0)

Cancel