Skip to content

Commit a850b03

Browse files
committed
Make UhidManager compatible with API 19
1 parent defe8c8 commit a850b03

File tree

1 file changed

+43
-56
lines changed

1 file changed

+43
-56
lines changed

server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,17 @@
88
import android.os.Build;
99
import android.os.HandlerThread;
1010
import android.os.MessageQueue;
11-
import android.system.ErrnoException;
12-
import android.system.Os;
13-
import android.system.OsConstants;
11+
import android.os.Process;
1412
import android.util.ArrayMap;
1513

16-
import androidx.annotation.RequiresApi;
17-
1814
import java.io.FileDescriptor;
1915
import java.io.IOException;
20-
import java.io.InterruptedIOException;
16+
import java.io.RandomAccessFile;
2117
import java.nio.ByteBuffer;
2218
import java.nio.ByteOrder;
19+
import java.nio.channels.FileChannel;
2320
import java.nio.charset.StandardCharsets;
2421

25-
@RequiresApi(AndroidVersions.API_21_ANDROID_5_0)
2622
public 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

Comments
 (0)