88import android .os .Build ;
99import android .os .HandlerThread ;
1010import android .os .MessageQueue ;
11- import android .system .ErrnoException ;
12- import android .system .Os ;
13- import android .system .OsConstants ;
11+ import android .os .Process ;
1412import android .util .ArrayMap ;
1513
16- import androidx .annotation .RequiresApi ;
17-
1814import java .io .FileDescriptor ;
1915import java .io .IOException ;
20- import java .io .InterruptedIOException ;
16+ import java .io .RandomAccessFile ;
2117import java .nio .ByteBuffer ;
2218import java .nio .ByteOrder ;
19+ import java .nio .channels .FileChannel ;
2320import java .nio .charset .StandardCharsets ;
2421
25- @ RequiresApi (AndroidVersions .API_21_ANDROID_5_0 )
2622public final class UhidManager {
2723
2824 // Linux: include/uapi/linux/uhid.h
@@ -36,11 +32,11 @@ public final class UhidManager {
3632 private static final int SIZE_OF_UHID_EVENT = 4380 ; // sizeof(struct uhid_event)
3733
3834 // Must be unique across the system
39- private static final String INPUT_PORT = "scrcpy:" + Os . getpid ();
35+ private static final String INPUT_PORT = "scrcpy:" + Process . myPid ();
4036
4137 private final String displayUniqueId ;
4238
43- private final ArrayMap <Integer , FileDescriptor > fds = new ArrayMap <>();
39+ private final ArrayMap <Integer , RandomAccessFile > rafs = new ArrayMap <>();
4440 private final ByteBuffer buffer = ByteBuffer .allocate (SIZE_OF_UHID_EVENT ).order (ByteOrder .nativeOrder ());
4541
4642 private final DeviceMessageSender sender ;
@@ -59,41 +55,35 @@ public UhidManager(DeviceMessageSender sender, String displayUniqueId) {
5955 }
6056
6157 public void open (int id , int vendorId , int productId , String name , byte [] reportDesc ) throws IOException {
62- try {
63- FileDescriptor fd = Os .open ("/dev/uhid" , OsConstants .O_RDWR , 0 );
64- try {
65- // First UHID device added
66- boolean firstDevice = fds .isEmpty ();
67-
68- FileDescriptor old = fds .put (id , fd );
69- if (old != null ) {
70- Ln .w ("Duplicate UHID id: " + id );
71- close (old );
72- }
58+ try (RandomAccessFile raf = new RandomAccessFile ("/dev/uhid" , "rw" )) {
59+ // First UHID device added
60+ boolean firstDevice = rafs .isEmpty ();
61+
62+ RandomAccessFile old = rafs .put (id , raf );
63+ if (old != null ) {
64+ Ln .w ("Duplicate UHID id: " + id );
65+ close (old );
66+ }
7367
74- String phys = mustUseInputPort () ? INPUT_PORT : null ;
75- byte [] req = buildUhidCreate2Req (vendorId , productId , name , reportDesc , phys );
76- Os .write (fd , req , 0 , req .length );
68+ String phys = mustUseInputPort () ? INPUT_PORT : null ;
69+ byte [] req = buildUhidCreate2Req (vendorId , productId , name , reportDesc , phys );
70+ raf .write (req , 0 , req .length );
7771
78- if (firstDevice ) {
79- addUniqueIdAssociation ();
80- }
81- registerUhidListener (id , fd );
82- } catch (Exception e ) {
83- close (fd );
84- throw e ;
72+ if (firstDevice ) {
73+ addUniqueIdAssociation ();
8574 }
86- } catch (ErrnoException e ) {
87- throw new IOException (e );
75+ registerUhidListener (id , raf );
8876 }
8977 }
9078
91- private void registerUhidListener (int id , FileDescriptor fd ) {
79+ private void registerUhidListener (int id , RandomAccessFile raf ) throws IOException {
9280 if (Build .VERSION .SDK_INT >= AndroidVersions .API_23_ANDROID_6_0 ) {
81+ final FileDescriptor fd = raf .getFD ();
82+ final FileChannel channel = raf .getChannel ();
9383 queue .addOnFileDescriptorEventListener (fd , MessageQueue .OnFileDescriptorEventListener .EVENT_INPUT , (fd2 , events ) -> {
9484 try {
9585 buffer .clear ();
96- int r = Os .read (fd2 , buffer );
86+ int r = channel .read (buffer );
9787 buffer .flip ();
9888 if (r > 0 ) {
9989 int type = buffer .getInt ();
@@ -105,7 +95,7 @@ private void registerUhidListener(int id, FileDescriptor fd) {
10595 }
10696 }
10797 }
108- } catch (ErrnoException | InterruptedIOException e ) {
98+ } catch (IOException e ) {
10999 Ln .e ("Failed to read UHID output" , e );
110100 return 0 ;
111101 }
@@ -114,8 +104,9 @@ private void registerUhidListener(int id, FileDescriptor fd) {
114104 }
115105 }
116106
117- private void unregisterUhidListener (FileDescriptor fd ) {
107+ private void unregisterUhidListener (RandomAccessFile raf ) throws IOException {
118108 if (Build .VERSION .SDK_INT >= AndroidVersions .API_23_ANDROID_6_0 ) {
109+ final FileDescriptor fd = raf .getFD ();
119110 queue .removeOnFileDescriptorEventListener (fd );
120111 }
121112 }
@@ -151,18 +142,14 @@ private static byte[] extractHidOutputData(ByteBuffer buffer) {
151142 }
152143
153144 public void writeInput (int id , byte [] data ) throws IOException {
154- FileDescriptor fd = fds .get (id );
155- if (fd == null ) {
145+ RandomAccessFile raf = rafs .get (id );
146+ if (raf == null ) {
156147 Ln .w ("Unknown UHID id: " + id );
157148 return ;
158149 }
159150
160- try {
161- byte [] req = buildUhidInput2Req (data );
162- Os .write (fd , req , 0 , req .length );
163- } catch (ErrnoException e ) {
164- throw new IOException (e );
165- }
151+ byte [] req = buildUhidInput2Req (data );
152+ raf .write (req , 0 , req .length );
166153 }
167154
168155 private static byte [] buildUhidCreate2Req (int vendorId , int productId , String name , byte [] reportDesc , String phys ) {
@@ -235,15 +222,15 @@ private static byte[] buildUhidInput2Req(byte[] data) {
235222 return buf .array ();
236223 }
237224
238- public void close (int id ) {
225+ public void close (int id ) throws IOException {
239226 // Linux: Documentation/hid/uhid.rst
240227 // If you close() the fd, the device is automatically unregistered and destroyed internally.
241- FileDescriptor fd = fds .remove (id );
242- if (fd != null ) {
243- unregisterUhidListener (fd );
244- close (fd );
228+ RandomAccessFile raf = rafs .remove (id );
229+ if (raf != null ) {
230+ unregisterUhidListener (raf );
231+ close (raf );
245232
246- if (fds .isEmpty ()) {
233+ if (rafs .isEmpty ()) {
247234 // Last UHID device removed
248235 removeUniqueIdAssociation ();
249236 }
@@ -253,21 +240,21 @@ public void close(int id) {
253240 }
254241
255242 public void closeAll () {
256- if (fds .isEmpty ()) {
243+ if (rafs .isEmpty ()) {
257244 return ;
258245 }
259246
260- for (FileDescriptor fd : fds .values ()) {
261- close (fd );
247+ for (RandomAccessFile raf : rafs .values ()) {
248+ close (raf );
262249 }
263250
264251 removeUniqueIdAssociation ();
265252 }
266253
267- private static void close (FileDescriptor fd ) {
254+ private static void close (RandomAccessFile raf ) {
268255 try {
269- Os .close (fd );
270- } catch (ErrnoException e ) {
256+ raf .close ();
257+ } catch (IOException e ) {
271258 Ln .e ("Failed to close uhid: " + e .getMessage ());
272259 }
273260 }
0 commit comments