Search code examples
androidproximitysensor

WakeLockWrapper Causing Memory Leak


I am implementing a call answer screen. In this screen, I am using both proximity sensor and power manager wake lock to create the effect of screen turning off when the phone is close to your face. I've managed to implement the feature, however it is causing memory leak. Since I detected the leak when the fragment is still simple and contains few code, I've removed several classes and functions to trace and confirm the cause of the leak. I've managed to narrow down the cause of the leak to PowerManager.WakeLock.

[![enter image description here](https://i.sstatic.net/bbL4a.png)](https://i.sstatic.net/bbL4a.png)

enter image description here

this is the code that I use to implement the feature in the fragment. I've tried to release the wake lock on multiple point in fragment lifecycle, however it still causes memory leak.


override val sensorManager: SensorManager
        get() = requireContext().getSystemService(Context.SENSOR_SERVICE) as SensorManager
    override var proximitySensor: Sensor? = null
    override val powerManager: PowerManager =
        requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
    override val lock: PowerManager.WakeLock = powerManager.newWakeLock(
        PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
        PROXIMITY_WAKE_LOG_TAG
    )

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

        activity?.onBackPressedDispatcher?.addCallback {
            activity?.finishAndRemoveTask()
        }

    }

override fun onResume() {
        super.onResume()
        proximitySensor?.let { proximity ->
            sensorManager.apply {
                registerListener(
                    this@AnswerFragment,
                    proximity,
                    SensorManager.SENSOR_DELAY_NORMAL
                )
            }
        }
    }

override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
        if (lock.isHeld) {
            lock.release()
        }
    }

override fun onDestroyView() {
        super.onDestroyView()
        proximitySensor = null
        if (lock.isHeld) {
            lock.release()
        }
        _binding = null
    }

override fun onDestroy() {
        if (lock.isHeld) {
            lock.release()
        }
        super.onDestroy()
    }

override fun onSensorChanged(event: SensorEvent?) {
        if (event?.values?.get(0) == 0.0f) {
            // Object is near phone, turn off screen
            lock.acquire()
        } else {
            // Object is not near phone, turn on screen
            if (lock.isHeld) {
                lock.release()
            }
        }
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}

As a side note: I am also getting this error in my log

WakeLock finalized while still held


Solution

  • This is a known issue. See the LeakCanary issue and the underlying tools issue. For now, I recommend that you consider it to be a false positive, and ignore the leak.