Skip to content

Commit b3279b8

Browse files
committed
Hold Wi-Fi and CPU wakelocks to prevent sleeping while serving USB devices. Add a UI to start and stop the service.
1 parent 82cfa0b commit b3279b8

File tree

4 files changed

+128
-32
lines changed

4 files changed

+128
-32
lines changed

src/org/cgutman/usbip/config/UsbIpConfig.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,51 @@
66
import android.app.Activity;
77
import android.content.Intent;
88
import android.os.Bundle;
9+
import android.view.View;
10+
import android.view.View.OnClickListener;
11+
import android.widget.Button;
12+
import android.widget.TextView;
913

1014
public class UsbIpConfig extends Activity {
15+
private Button serviceButton;
16+
private TextView serviceStatus;
17+
18+
private boolean running = false;
19+
20+
private void updateStatus() {
21+
if (running) {
22+
serviceButton.setText("Stop Service");
23+
serviceStatus.setText("USB/IP Service Running");
24+
}
25+
else {
26+
serviceButton.setText("Start Service");
27+
serviceStatus.setText("USB/IP Service Stopped");
28+
}
29+
}
30+
1131
@Override
1232
protected void onCreate(Bundle savedInstanceState) {
1333
super.onCreate(savedInstanceState);
1434
setContentView(R.layout.activity_usbip_config);
35+
36+
serviceButton = (Button) findViewById(R.id.serviceButton);
37+
serviceStatus = (TextView) findViewById(R.id.serviceStatus);
38+
39+
updateStatus();
1540

16-
startService(new Intent(this, UsbIpService.class));
41+
serviceButton.setOnClickListener(new OnClickListener() {
42+
@Override
43+
public void onClick(View v) {
44+
if (running) {
45+
stopService(new Intent(UsbIpConfig.this, UsbIpService.class));
46+
}
47+
else {
48+
startService(new Intent(UsbIpConfig.this, UsbIpService.class));
49+
}
50+
51+
running = !running;
52+
updateStatus();
53+
}
54+
});
1755
}
1856
}

src/org/cgutman/usbip/server/UsbIpServer.java

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import java.io.OutputStream;
66
import java.net.ServerSocket;
77
import java.net.Socket;
8-
import java.util.ArrayList;
8+
import java.util.Map;
9+
import java.util.concurrent.ConcurrentHashMap;
910

1011
import org.cgutman.usbip.server.protocol.ProtoDefs;
1112
import org.cgutman.usbip.server.protocol.cli.CommonPacket;
@@ -18,9 +19,10 @@
1819
public class UsbIpServer {
1920
public static final int PORT = 3240;
2021

21-
private ArrayList<Thread> threads = new ArrayList<Thread>();
2222
private UsbRequestHandler handler;
23+
private Thread serverThread;
2324
private ServerSocket serverSock;
25+
private ConcurrentHashMap<Socket, Thread> connections = new ConcurrentHashMap<Socket, Thread>();
2426

2527
// Returns true if a device is now attached
2628
private boolean handleRequest(InputStream in, OutputStream out) throws IOException {
@@ -66,12 +68,11 @@ else if (inMsg.code == ProtoDefs.OP_REQ_IMPORT) {
6668
return res;
6769
}
6870

69-
private boolean handleDevRequest(InputStream in, OutputStream out) throws IOException {
70-
UsbIpDevicePacket inMsg = UsbIpDevicePacket.read(in);
71+
private boolean handleDevRequest(Socket s) throws IOException {
72+
UsbIpDevicePacket inMsg = UsbIpDevicePacket.read(s.getInputStream());
7173

72-
//System.out.println(inMsg);
7374
if (inMsg.command == UsbIpDevicePacket.USBIP_CMD_SUBMIT) {
74-
handler.submitUrbRequest(out, (UsbIpSubmitUrb) inMsg);
75+
handler.submitUrbRequest(s, (UsbIpSubmitUrb) inMsg);
7576
}
7677
else {
7778
return false;
@@ -80,6 +81,20 @@ private boolean handleDevRequest(InputStream in, OutputStream out) throws IOExce
8081
return true;
8182
}
8283

84+
public void killClient(Socket s) {
85+
Thread t = connections.remove(s);
86+
87+
try {
88+
s.close();
89+
} catch (IOException e) {}
90+
91+
t.interrupt();
92+
93+
try {
94+
t.join();
95+
} catch (InterruptedException e) {}
96+
}
97+
8398
private void handleClient(final Socket s) {
8499
Thread t = new Thread() {
85100
@Override
@@ -92,7 +107,7 @@ public void run() {
92107
OutputStream out = s.getOutputStream();
93108
while (!isInterrupted()) {
94109
if (handleRequest(in, out)) {
95-
while (handleDevRequest(in, out));
110+
while (handleDevRequest(s));
96111
}
97112
}
98113
} catch (IOException e) {
@@ -104,8 +119,8 @@ public void run() {
104119
}
105120
}
106121
};
107-
108-
threads.add(t);
122+
123+
connections.put(s, t);
109124
t.start();
110125
}
111126

@@ -127,7 +142,8 @@ public void run() {
127142
}
128143
}
129144
};
130-
threads.add(t);
145+
146+
serverThread = t;
131147
t.start();
132148
}
133149

@@ -136,13 +152,29 @@ public void stop() {
136152
try {
137153
serverSock.close();
138154
} catch (IOException e) {}
155+
156+
serverSock = null;
139157
}
140158

141-
for (Thread t : threads) {
142-
t.interrupt();
159+
if (serverThread != null) {
160+
serverThread.interrupt();
161+
162+
try {
163+
serverThread.join();
164+
} catch (InterruptedException e) {}
165+
166+
serverThread = null;
167+
}
168+
169+
for (Map.Entry<Socket, Thread> entry : connections.entrySet()) {
170+
try {
171+
entry.getKey().close();
172+
} catch (IOException e) {}
173+
174+
entry.getValue().interrupt();
143175

144176
try {
145-
t.join();
177+
entry.getValue().join();
146178
} catch (InterruptedException e) {}
147179
}
148180
}

src/org/cgutman/usbip/server/UsbRequestHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.cgutman.usbip.server;
22

3-
import java.io.OutputStream;
3+
import java.net.Socket;
44
import java.util.List;
55

66
import org.cgutman.usbip.server.protocol.dev.UsbIpSubmitUrb;
@@ -12,5 +12,5 @@ public interface UsbRequestHandler {
1212
public boolean attachToDevice(String busId);
1313
public void detachFromDevice(String busId);
1414

15-
public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg);
15+
public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg);
1616
}

src/org/cgutman/usbip/service/UsbIpService.java

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package org.cgutman.usbip.service;
22

33
import java.io.IOException;
4-
import java.io.OutputStream;
4+
import java.net.Socket;
55
import java.nio.ByteBuffer;
66
import java.nio.ByteOrder;
77
import java.util.ArrayList;
@@ -40,16 +40,23 @@
4040
import android.hardware.usb.UsbInterface;
4141
import android.hardware.usb.UsbManager;
4242
import android.hardware.usb.UsbRequest;
43+
import android.net.wifi.WifiManager;
44+
import android.net.wifi.WifiManager.WifiLock;
4345
import android.os.Build;
4446
import android.os.IBinder;
47+
import android.os.PowerManager;
48+
import android.os.PowerManager.WakeLock;
4549
import android.util.SparseArray;
4650

4751
public class UsbIpService extends Service implements UsbRequestHandler {
4852

4953
private UsbManager usbManager;
54+
5055
private SparseArray<AttachedDeviceContext> connections;
5156
private SparseArray<Boolean> permission;
5257
private UsbIpServer server;
58+
private WakeLock cpuWakeLock;
59+
private WifiLock wifiLock;
5360

5461
private static final int NOTIFICATION_ID = 100;
5562

@@ -100,20 +107,39 @@ private void updateNotification() {
100107
public void onCreate() {
101108
super.onCreate();
102109

103-
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
110+
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
104111
connections = new SparseArray<AttachedDeviceContext>();
105112
permission = new SparseArray<Boolean>();
106113

107114
usbPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
108115
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
109116
registerReceiver(usbReceiver, filter);
110117

118+
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
119+
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
120+
121+
cpuWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "USB/IP Service");
122+
cpuWakeLock.acquire();
123+
124+
wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "USB/IP Service");
125+
wifiLock.acquire();
126+
111127
server = new UsbIpServer();
112128
server.start(this);
113129

114130
updateNotification();
115131
}
116132

133+
public void onDestroy() {
134+
super.onDestroy();
135+
136+
server.stop();
137+
unregisterReceiver(usbReceiver);
138+
139+
wifiLock.release();
140+
cpuWakeLock.release();
141+
}
142+
117143
@Override
118144
public IBinder onBind(Intent intent) {
119145
// Not currently bindable
@@ -289,12 +315,12 @@ public static void dumpInterfaces(UsbDevice dev) {
289315
}
290316
}
291317

292-
private static void sendReply(OutputStream out, UsbIpSubmitUrbReply reply, int status) {
318+
private static void sendReply(Socket s, UsbIpSubmitUrbReply reply, int status) {
293319
reply.status = status;
294320
try {
295321
// We need to synchronize to avoid writing on top of ourselves
296-
synchronized (out) {
297-
out.write(reply.serialize());
322+
synchronized (s) {
323+
s.getOutputStream().write(reply.serialize());
298324
}
299325
} catch (IOException e) {
300326
e.printStackTrace();
@@ -303,7 +329,7 @@ private static void sendReply(OutputStream out, UsbIpSubmitUrbReply reply, int s
303329

304330
// FIXME: This dispatching could use some refactoring so we don't have to pass
305331
// a million parameters to this guy
306-
private void dispatchRequest(final AttachedDeviceContext context, final OutputStream replyOut,
332+
private void dispatchRequest(final AttachedDeviceContext context, final Socket s,
307333
final UsbEndpoint selectedEndpoint, final ByteBuffer buff, final UsbIpSubmitUrb msg) {
308334
context.requestPool.submit(new Runnable() {
309335
@Override
@@ -333,7 +359,7 @@ public void run() {
333359
reply.actualLength = res;
334360
reply.status = ProtoDefs.ST_OK;
335361
}
336-
sendReply(replyOut, reply, reply.status);
362+
sendReply(s, reply, reply.status);
337363
}
338364
else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
339365
System.out.printf("Interrupt transfer - %d bytes %s on EP %d\n",
@@ -352,7 +378,7 @@ else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
352378
req.setClientData(urbCtxt);
353379
if (!req.queue(buff, msg.transferBufferLength)) {
354380
System.err.println("Failed to queue request");
355-
sendReply(replyOut, reply, ProtoDefs.ST_NA);
381+
sendReply(s, reply, ProtoDefs.ST_NA);
356382
req.close();
357383
return;
358384
}
@@ -397,30 +423,30 @@ else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
397423
// so I'm not going to...
398424
reply.startFrame = 0;
399425

400-
sendReply(replyOut, reply, reply.status);
426+
sendReply(s, reply, reply.status);
401427
}
402428
else {
403429
System.err.println("Unsupported endpoint type: "+selectedEndpoint.getType());
404-
sendReply(replyOut, reply, ProtoDefs.ST_NA);
430+
sendReply(s, reply, ProtoDefs.ST_NA);
405431
}
406432
}
407433
});
408434
}
409435

410436
@Override
411-
public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {
437+
public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg) {
412438
UsbIpSubmitUrbReply reply = new UsbIpSubmitUrbReply(msg.seqNum,
413439
msg.devId, msg.direction, msg.ep);
414440

415441
UsbDevice dev = getDevice(msg.devId);
416442
if (dev == null) {
417-
sendReply(replyOut, reply, ProtoDefs.ST_NA);
443+
sendReply(s, reply, ProtoDefs.ST_NA);
418444
return;
419445
}
420446

421447
AttachedDeviceContext context = connections.get(msg.devId);
422448
if (context == null) {
423-
sendReply(replyOut, reply, ProtoDefs.ST_NA);
449+
sendReply(s, reply, ProtoDefs.ST_NA);
424450
return;
425451
}
426452

@@ -451,7 +477,7 @@ public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {
451477
reply.status = ProtoDefs.ST_OK;
452478
}
453479

454-
sendReply(replyOut, reply, reply.status);
480+
sendReply(s, reply, reply.status);
455481
return;
456482
}
457483
else {
@@ -490,7 +516,7 @@ public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {
490516

491517
if (selectedEndpoint == null) {
492518
System.err.println("EP not found: "+msg.ep);
493-
sendReply(replyOut, reply, ProtoDefs.ST_NA);
519+
sendReply(s, reply, ProtoDefs.ST_NA);
494520
return;
495521
}
496522

@@ -505,7 +531,7 @@ public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {
505531
}
506532

507533
// Dispatch this request asynchronously
508-
dispatchRequest(context, replyOut, selectedEndpoint, buff, msg);
534+
dispatchRequest(context, s, selectedEndpoint, buff, msg);
509535
}
510536
}
511537

0 commit comments

Comments
 (0)