When trying to read input_events from /dev/input/event16 I noticed that the size of the buffer I'm reading into may cause an exception. Here is the code I wrote:
public static void main(String[] args) throws IOException{
FileInputStream is = new FileInputStream("/dev/input/event16");
byte[] three_bytes = new byte[3];
byte[] twentyfour_bytes = new byte[24];
is.read(three_bytes); // fails
is.read(twentyfour_bytes); // does not fail
}
My initial experiments suggest that the buffer needs capacity for at least one full input_event struct. But I could not find out why.
The problem is the line is.read(three_bytes); causes the follwoing exception:
Exception in thread "main" java.io.IOException: Invalid argument
at java.base/java.io.FileInputStream.readBytes(Native Method)
at java.base/java.io.FileInputStream.read(FileInputStream.java:249)
at main.Test.main(Test.java:11)
I would like to figure out why the line is.read(three_bytes); throws the exception while is.read(twentyfour_bytes); reads the data as expected
For a start,
/dev/input/event16is not a regular file. It is a device file, and device files often don't behave like regular files.In this case, the
/dev/input/event*device files are for reading events from input devices. When you perform areadsyscall on them, they will return one or more complete events. These are binary data whose format is given by the following Cstruct:The size of that struct is (presumably) 24 bytes on a typical 64bit Linux system, though.
The behavior of the event devices is documented in Linux Input drivers v1.0, section 5. It states that a
readwill always give a whole number ofinput_eventstructs.It follows that the
readsyscall provides a buffer that is less thansizeof(input_event), the kernel cannot return anything. Apparently, this causes thereadsyscall to fail with errno valueEINVAL. (IMO, this is a reasonable design choice, and consistent with the documented meaning ofEINVAL.)So, in Java, when you call
read(three_bytes), that will map to areadsyscall with a read size of 3 bytes which fails; see above. The syscall failure is signaled to the Java application by throw anIOException.