Last post, File descriptor leak - HandlerThread, we’ve talked about how the HandlerThread
could potentially cause file descriptor leak.
But we still see file descriptor leak and RuntimeException
like before:
What happens
We know that’s because something keeps the fd
, and we fail to remove it when we don’t need it. After seeking for a while, we finally find that’s because of the two reasons:
- Misused Dagger while designing the class hierarchy, which will make Dagger inject the same dependencies for a few times.
- Dagger can guarantee the instance of the dependencies will be the same. But initializations after will still be triggered.
So our problem should be:
- The SensorManager inside one of the dependencies get initialized for a multiple time.
SensorManager
We need SensorManager
to assign a listener for handling event that sends back by the audio service. After debugging, we know the instance of SensorManager
is a SystemSensorManager
.
And we’ve noticed that if we don’t use registerListener()
to assign a listener, we won’t have fd
leak, so let’s look at how it works.
registerListener()
will get anSensorEventQueue
first:
- With the
SensorEventQueue
, theinternalQueue
, we can fetch anfd
from aSensorChannel
, and add intoLooper
. In here it should be the mainLooper
:
Until now, we know when every time we call the registerListener()
, we will get a fd
from it. And we don’t need to dig into the source code to know the fd
will be collected once you call the unregisterListener()
with the same listener.
Listeners inside SensorManager
The whole process for registering/unregistering a listener to the SensorManager
seems fine. But let’s look at registerListener()
again:
// In SystemSensorManager.java |
It’s clear the listener will be used as the key in a HashMap
, and the value is SensorEventQueue
, which will get a fd
inside.
And for unregisterListener()
:
// In SystemSensorManager.java |
You can see it only remove the listener and close the queue one at a time. If we call the method with different listener multiple times, just like our case, we will need to keep all the listeners by ourself. Or we may lose the references to the listeners and a few listeners will be left inside the SensorManager
.
How to solve
The solution is simple since it’s wrong for Dagger to inject the same dependencies for a multiple times. Solve the injection issue, we solve the file descriptor leak.
What’s more
Even we don’t get the exception caused by the InputChannel
, we may encounter another exception since there is a limit for the number of listeners inside SensorManager
:
// In SystemSensorManager.java |