diff --git a/src/org/cgutman/usbip/config/UsbIpConfig.java b/src/org/cgutman/usbip/config/UsbIpConfig.java index 3e37953..a0538c6 100644 --- a/src/org/cgutman/usbip/config/UsbIpConfig.java +++ b/src/org/cgutman/usbip/config/UsbIpConfig.java @@ -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(); + } + }); } } diff --git a/src/org/cgutman/usbip/server/UsbIpServer.java b/src/org/cgutman/usbip/server/UsbIpServer.java index d31122f..671e200 100644 --- a/src/org/cgutman/usbip/server/UsbIpServer.java +++ b/src/org/cgutman/usbip/server/UsbIpServer.java @@ -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; @@ -18,9 +19,10 @@ public class UsbIpServer { public static final int PORT = 3240; - private ArrayList threads = new ArrayList(); private UsbRequestHandler handler; + private Thread serverThread; private ServerSocket serverSock; + private ConcurrentHashMap connections = new ConcurrentHashMap(); // Returns true if a device is now attached private boolean handleRequest(InputStream in, OutputStream out) throws IOException { @@ -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; @@ -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 @@ -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) { @@ -104,8 +119,8 @@ public void run() { } } }; - - threads.add(t); + + connections.put(s, t); t.start(); } @@ -127,7 +142,8 @@ public void run() { } } }; - threads.add(t); + + serverThread = t; t.start(); } @@ -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 entry : connections.entrySet()) { + try { + entry.getKey().close(); + } catch (IOException e) {} + + entry.getValue().interrupt(); try { - t.join(); + entry.getValue().join(); } catch (InterruptedException e) {} } } diff --git a/src/org/cgutman/usbip/server/UsbRequestHandler.java b/src/org/cgutman/usbip/server/UsbRequestHandler.java index 13df6a3..0fddafb 100644 --- a/src/org/cgutman/usbip/server/UsbRequestHandler.java +++ b/src/org/cgutman/usbip/server/UsbRequestHandler.java @@ -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; @@ -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); } diff --git a/src/org/cgutman/usbip/service/UsbIpService.java b/src/org/cgutman/usbip/service/UsbIpService.java index 891ec02..9e19465 100644 --- a/src/org/cgutman/usbip/service/UsbIpService.java +++ b/src/org/cgutman/usbip/service/UsbIpService.java @@ -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; @@ -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 connections; private SparseArray permission; private UsbIpServer server; + private WakeLock cpuWakeLock; + private WifiLock wifiLock; private static final int NOTIFICATION_ID = 100; @@ -100,7 +107,7 @@ private void updateNotification() { public void onCreate() { super.onCreate(); - usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); connections = new SparseArray(); permission = new SparseArray(); @@ -108,12 +115,31 @@ public void onCreate() { 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 @@ -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(); @@ -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 @@ -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", @@ -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; } @@ -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; } @@ -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 { @@ -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; } @@ -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); } }