Skip to content

Commit

Permalink
Hold Wi-Fi and CPU wakelocks to prevent sleeping while serving USB de…
Browse files Browse the repository at this point in the history
…vices. Add a UI to start and stop the service.
  • Loading branch information
cgutman committed Jul 27, 2014
1 parent 82cfa0b commit b3279b8
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 32 deletions.
40 changes: 39 additions & 1 deletion src/org/cgutman/usbip/config/UsbIpConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,51 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class UsbIpConfig extends Activity {
private Button serviceButton;
private TextView serviceStatus;

private boolean running = false;

private void updateStatus() {
if (running) {
serviceButton.setText("Stop Service");
serviceStatus.setText("USB/IP Service Running");
}
else {
serviceButton.setText("Start Service");
serviceStatus.setText("USB/IP Service Stopped");
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_usbip_config);

serviceButton = (Button) findViewById(R.id.serviceButton);
serviceStatus = (TextView) findViewById(R.id.serviceStatus);

updateStatus();

startService(new Intent(this, UsbIpService.class));
serviceButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (running) {
stopService(new Intent(UsbIpConfig.this, UsbIpService.class));
}
else {
startService(new Intent(UsbIpConfig.this, UsbIpService.class));
}

running = !running;
updateStatus();
}
});
}
}
58 changes: 45 additions & 13 deletions src/org/cgutman/usbip/server/UsbIpServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

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

private ArrayList<Thread> threads = new ArrayList<Thread>();
private UsbRequestHandler handler;
private Thread serverThread;
private ServerSocket serverSock;
private ConcurrentHashMap<Socket, Thread> connections = new ConcurrentHashMap<Socket, Thread>();

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

private boolean handleDevRequest(InputStream in, OutputStream out) throws IOException {
UsbIpDevicePacket inMsg = UsbIpDevicePacket.read(in);
private boolean handleDevRequest(Socket s) throws IOException {
UsbIpDevicePacket inMsg = UsbIpDevicePacket.read(s.getInputStream());

//System.out.println(inMsg);
if (inMsg.command == UsbIpDevicePacket.USBIP_CMD_SUBMIT) {
handler.submitUrbRequest(out, (UsbIpSubmitUrb) inMsg);
handler.submitUrbRequest(s, (UsbIpSubmitUrb) inMsg);
}
else {
return false;
Expand All @@ -80,6 +81,20 @@ private boolean handleDevRequest(InputStream in, OutputStream out) throws IOExce
return true;
}

public void killClient(Socket s) {
Thread t = connections.remove(s);

try {
s.close();
} catch (IOException e) {}

t.interrupt();

try {
t.join();
} catch (InterruptedException e) {}
}

private void handleClient(final Socket s) {
Thread t = new Thread() {
@Override
Expand All @@ -92,7 +107,7 @@ public void run() {
OutputStream out = s.getOutputStream();
while (!isInterrupted()) {
if (handleRequest(in, out)) {
while (handleDevRequest(in, out));
while (handleDevRequest(s));
}
}
} catch (IOException e) {
Expand All @@ -104,8 +119,8 @@ public void run() {
}
}
};
threads.add(t);

connections.put(s, t);
t.start();
}

Expand All @@ -127,7 +142,8 @@ public void run() {
}
}
};
threads.add(t);

serverThread = t;
t.start();
}

Expand All @@ -136,13 +152,29 @@ public void stop() {
try {
serverSock.close();
} catch (IOException e) {}

serverSock = null;
}

for (Thread t : threads) {
t.interrupt();
if (serverThread != null) {
serverThread.interrupt();

try {
serverThread.join();
} catch (InterruptedException e) {}

serverThread = null;
}

for (Map.Entry<Socket, Thread> entry : connections.entrySet()) {
try {
entry.getKey().close();
} catch (IOException e) {}

entry.getValue().interrupt();

try {
t.join();
entry.getValue().join();
} catch (InterruptedException e) {}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/org/cgutman/usbip/server/UsbRequestHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.cgutman.usbip.server;

import java.io.OutputStream;
import java.net.Socket;
import java.util.List;

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

public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg);
public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg);
}
58 changes: 42 additions & 16 deletions src/org/cgutman/usbip/service/UsbIpService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.cgutman.usbip.service;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
Expand Down Expand Up @@ -40,16 +40,23 @@
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.SparseArray;

public class UsbIpService extends Service implements UsbRequestHandler {

private UsbManager usbManager;

private SparseArray<AttachedDeviceContext> connections;
private SparseArray<Boolean> permission;
private UsbIpServer server;
private WakeLock cpuWakeLock;
private WifiLock wifiLock;

private static final int NOTIFICATION_ID = 100;

Expand Down Expand Up @@ -100,20 +107,39 @@ private void updateNotification() {
public void onCreate() {
super.onCreate();

usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
connections = new SparseArray<AttachedDeviceContext>();
permission = new SparseArray<Boolean>();

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

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);

cpuWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "USB/IP Service");
cpuWakeLock.acquire();

wifiLock = wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "USB/IP Service");
wifiLock.acquire();

server = new UsbIpServer();
server.start(this);

updateNotification();
}

public void onDestroy() {
super.onDestroy();

server.stop();
unregisterReceiver(usbReceiver);

wifiLock.release();
cpuWakeLock.release();
}

@Override
public IBinder onBind(Intent intent) {
// Not currently bindable
Expand Down Expand Up @@ -289,12 +315,12 @@ public static void dumpInterfaces(UsbDevice dev) {
}
}

private static void sendReply(OutputStream out, UsbIpSubmitUrbReply reply, int status) {
private static void sendReply(Socket s, UsbIpSubmitUrbReply reply, int status) {
reply.status = status;
try {
// We need to synchronize to avoid writing on top of ourselves
synchronized (out) {
out.write(reply.serialize());
synchronized (s) {
s.getOutputStream().write(reply.serialize());
}
} catch (IOException e) {
e.printStackTrace();
Expand All @@ -303,7 +329,7 @@ private static void sendReply(OutputStream out, UsbIpSubmitUrbReply reply, int s

// FIXME: This dispatching could use some refactoring so we don't have to pass
// a million parameters to this guy
private void dispatchRequest(final AttachedDeviceContext context, final OutputStream replyOut,
private void dispatchRequest(final AttachedDeviceContext context, final Socket s,
final UsbEndpoint selectedEndpoint, final ByteBuffer buff, final UsbIpSubmitUrb msg) {
context.requestPool.submit(new Runnable() {
@Override
Expand Down Expand Up @@ -333,7 +359,7 @@ public void run() {
reply.actualLength = res;
reply.status = ProtoDefs.ST_OK;
}
sendReply(replyOut, reply, reply.status);
sendReply(s, reply, reply.status);
}
else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
System.out.printf("Interrupt transfer - %d bytes %s on EP %d\n",
Expand All @@ -352,7 +378,7 @@ else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
req.setClientData(urbCtxt);
if (!req.queue(buff, msg.transferBufferLength)) {
System.err.println("Failed to queue request");
sendReply(replyOut, reply, ProtoDefs.ST_NA);
sendReply(s, reply, ProtoDefs.ST_NA);
req.close();
return;
}
Expand Down Expand Up @@ -397,30 +423,30 @@ else if (selectedEndpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
// so I'm not going to...
reply.startFrame = 0;

sendReply(replyOut, reply, reply.status);
sendReply(s, reply, reply.status);
}
else {
System.err.println("Unsupported endpoint type: "+selectedEndpoint.getType());
sendReply(replyOut, reply, ProtoDefs.ST_NA);
sendReply(s, reply, ProtoDefs.ST_NA);
}
}
});
}

@Override
public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {
public void submitUrbRequest(Socket s, UsbIpSubmitUrb msg) {
UsbIpSubmitUrbReply reply = new UsbIpSubmitUrbReply(msg.seqNum,
msg.devId, msg.direction, msg.ep);

UsbDevice dev = getDevice(msg.devId);
if (dev == null) {
sendReply(replyOut, reply, ProtoDefs.ST_NA);
sendReply(s, reply, ProtoDefs.ST_NA);
return;
}

AttachedDeviceContext context = connections.get(msg.devId);
if (context == null) {
sendReply(replyOut, reply, ProtoDefs.ST_NA);
sendReply(s, reply, ProtoDefs.ST_NA);
return;
}

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

sendReply(replyOut, reply, reply.status);
sendReply(s, reply, reply.status);
return;
}
else {
Expand Down Expand Up @@ -490,7 +516,7 @@ public void submitUrbRequest(OutputStream replyOut, UsbIpSubmitUrb msg) {

if (selectedEndpoint == null) {
System.err.println("EP not found: "+msg.ep);
sendReply(replyOut, reply, ProtoDefs.ST_NA);
sendReply(s, reply, ProtoDefs.ST_NA);
return;
}

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

// Dispatch this request asynchronously
dispatchRequest(context, replyOut, selectedEndpoint, buff, msg);
dispatchRequest(context, s, selectedEndpoint, buff, msg);
}
}

Expand Down

0 comments on commit b3279b8

Please sign in to comment.