From ebf5d6b2237de59a0c90947a21e03f55e64db4dc Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 12:31:27 +0200 Subject: [PATCH 1/6] AdbProtocolHandler: extract SyncTransport creation --- src/se/vidstige/jadb/server/AdbProtocolHandler.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index fffbed4..c541904 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -77,7 +77,7 @@ class AdbProtocolHandler implements Runnable { try { sync(output, input); } catch (JadbException e) { // sync response with a different type of fail message - SyncTransport sync = new SyncTransport(output, input); + SyncTransport sync = getSyncTransport(output, input); sync.send("FAIL", e.getMessage()); } } else if (command.startsWith("shell:")) { @@ -148,14 +148,14 @@ class AdbProtocolHandler implements Runnable { path = remotePath.substring(0, idx); mode = Integer.parseInt(remotePath.substring(idx + 1)); } - SyncTransport transport = new SyncTransport(output, input); + SyncTransport transport = getSyncTransport(output, input); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); transport.readChunksTo(buffer); selected.filePushed(new RemoteFile(path), mode, buffer); transport.sendStatus("OKAY", 0); // 0 = ignored } else if ("RECV".equals(id)) { String remotePath = readString(input, length); - SyncTransport transport = new SyncTransport(output, input); + SyncTransport transport = getSyncTransport(output, input); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); selected.filePulled(new RemoteFile(remotePath), buffer); transport.sendStream(new ByteArrayInputStream(buffer.toByteArray())); @@ -171,4 +171,8 @@ class AdbProtocolHandler implements Runnable { writer.writeBytes(getCommandLength(response)); writer.writeBytes(response); } + + private SyncTransport getSyncTransport(DataOutput output, DataInput input) { + return new SyncTransport(output, input); + } } From bc2c76486acf1bcddfe512f7c9a68d3d4d5d081e Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 12:37:55 +0200 Subject: [PATCH 2/6] AdbProtocolHandler: extract loop body to new method --- .../jadb/server/AdbProtocolHandler.java | 163 +++++++++--------- 1 file changed, 84 insertions(+), 79 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index c541904..ffc6986 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -40,88 +40,93 @@ class AdbProtocolHandler implements Runnable { DataInput input = new DataInputStream(socket.getInputStream()); DataOutputStream output = new DataOutputStream(socket.getOutputStream()); - while (true) { - byte[] buffer = new byte[4]; - input.readFully(buffer); - String encodedLength = new String(buffer, StandardCharsets.UTF_8); - int length = Integer.parseInt(encodedLength, 16); - - buffer = new byte[length]; - input.readFully(buffer); - String command = new String(buffer, StandardCharsets.UTF_8); - - responder.onCommand(command); - - try { - if ("host:version".equals(command)) { - output.writeBytes("OKAY"); - send(output, String.format("%04x", responder.getVersion())); - } else if ("host:transport-any".equals(command)) { - // TODO: Check so that exactly one device is selected. - selected = responder.getDevices().get(0); - output.writeBytes("OKAY"); - } else if ("host:devices".equals(command)) { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - DataOutputStream writer = new DataOutputStream(tmp); - for (AdbDeviceResponder d : responder.getDevices()) { - writer.writeBytes(d.getSerial() + "\t" + d.getType() + "\n"); - } - output.writeBytes("OKAY"); - send(output, new String(tmp.toByteArray(), StandardCharsets.UTF_8)); - } else if (command.startsWith("host:transport:")) { - String serial = command.substring("host:transport:".length()); - selected = findDevice(serial); - output.writeBytes("OKAY"); - } else if ("sync:".equals(command)) { - output.writeBytes("OKAY"); - try { - sync(output, input); - } catch (JadbException e) { // sync response with a different type of fail message - SyncTransport sync = getSyncTransport(output, input); - sync.send("FAIL", e.getMessage()); - } - } else if (command.startsWith("shell:")) { - String shellCommand = command.substring("shell:".length()); - output.writeBytes("OKAY"); - shell(shellCommand, output, input); - output.close(); - return; - } else if ("host:get-state".equals(command)) { - // TODO: Check so that exactly one device is selected. - AdbDeviceResponder device = responder.getDevices().get(0); - output.writeBytes("OKAY"); - send(output, device.getType()); - } else if (command.startsWith("host-serial:")) { - String[] strs = command.split(":",0); - if (strs.length != 3) { - throw new ProtocolException("Invalid command: " + command); - } - - String serial = strs[1]; - boolean found = false; - output.writeBytes("OKAY"); - for (AdbDeviceResponder d : responder.getDevices()) { - if (d.getSerial().equals(serial)) { - send(output, d.getType()); - found = true; - break; - } - } - - if (!found) { - send(output, "unknown"); - } - } else { - throw new ProtocolException("Unknown command: " + command); - } - } catch (ProtocolException e) { - output.writeBytes("FAIL"); - send(output, e.getMessage()); - } - output.flush(); + while (processCommand(input, output)) { + // nothing to do here } } + private boolean processCommand(DataInput input, DataOutputStream output) throws IOException { + byte[] buffer = new byte[4]; + input.readFully(buffer); + String encodedLength = new String(buffer, StandardCharsets.UTF_8); + int length = Integer.parseInt(encodedLength, 16); + + buffer = new byte[length]; + input.readFully(buffer); + String command = new String(buffer, StandardCharsets.UTF_8); + + responder.onCommand(command); + + try { + if ("host:version".equals(command)) { + output.writeBytes("OKAY"); + send(output, String.format("%04x", responder.getVersion())); + } else if ("host:transport-any".equals(command)) { + // TODO: Check so that exactly one device is selected. + selected = responder.getDevices().get(0); + output.writeBytes("OKAY"); + } else if ("host:devices".equals(command)) { + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + DataOutputStream writer = new DataOutputStream(tmp); + for (AdbDeviceResponder d : responder.getDevices()) { + writer.writeBytes(d.getSerial() + "\t" + d.getType() + "\n"); + } + output.writeBytes("OKAY"); + send(output, new String(tmp.toByteArray(), StandardCharsets.UTF_8)); + } else if (command.startsWith("host:transport:")) { + String serial = command.substring("host:transport:".length()); + selected = findDevice(serial); + output.writeBytes("OKAY"); + } else if ("sync:".equals(command)) { + output.writeBytes("OKAY"); + try { + sync(output, input); + } catch (JadbException e) { // sync response with a different type of fail message + SyncTransport sync = getSyncTransport(output, input); + sync.send("FAIL", e.getMessage()); + } + } else if (command.startsWith("shell:")) { + String shellCommand = command.substring("shell:".length()); + output.writeBytes("OKAY"); + shell(shellCommand, output, input); + output.close(); + return false; + } else if ("host:get-state".equals(command)) { + // TODO: Check so that exactly one device is selected. + AdbDeviceResponder device = responder.getDevices().get(0); + output.writeBytes("OKAY"); + send(output, device.getType()); + } else if (command.startsWith("host-serial:")) { + String[] strs = command.split(":",0); + if (strs.length != 3) { + throw new ProtocolException("Invalid command: " + command); + } + + String serial = strs[1]; + boolean found = false; + output.writeBytes("OKAY"); + for (AdbDeviceResponder d : responder.getDevices()) { + if (d.getSerial().equals(serial)) { + send(output, d.getType()); + found = true; + break; + } + } + + if (!found) { + send(output, "unknown"); + } + } else { + throw new ProtocolException("Unknown command: " + command); + } + } catch (ProtocolException e) { + output.writeBytes("FAIL"); + send(output, e.getMessage()); + } + output.flush(); + return true; + } + private void shell(String command, DataOutputStream stdout, DataInput stdin) throws IOException { selected.shell(command, stdout, stdin); } From 69695c5a4baa773228fcda491e2b8ac4386ad07b Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 12:52:27 +0200 Subject: [PATCH 3/6] AdbProtocolHandler: use try-with-resources --- src/se/vidstige/jadb/server/AdbProtocolHandler.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index ffc6986..9e88b1d 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -37,11 +37,13 @@ class AdbProtocolHandler implements Runnable { } private void runServer() throws IOException { - DataInput input = new DataInputStream(socket.getInputStream()); - DataOutputStream output = new DataOutputStream(socket.getOutputStream()); - - while (processCommand(input, output)) { + try ( + DataInputStream input = new DataInputStream(socket.getInputStream()); + DataOutputStream output = new DataOutputStream(socket.getOutputStream()) + ) { + while (processCommand(input, output)) { // nothing to do here + } } } @@ -89,7 +91,6 @@ class AdbProtocolHandler implements Runnable { String shellCommand = command.substring("shell:".length()); output.writeBytes("OKAY"); shell(shellCommand, output, input); - output.close(); return false; } else if ("host:get-state".equals(command)) { // TODO: Check so that exactly one device is selected. From 47612591371865ef0f7f599a93cc655983d56a93 Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 13:07:41 +0200 Subject: [PATCH 4/6] AdbProtocolHandler: refactor reading command from input stream --- .../jadb/server/AdbProtocolHandler.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index 9e88b1d..1c1621d 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -48,15 +48,7 @@ class AdbProtocolHandler implements Runnable { } private boolean processCommand(DataInput input, DataOutputStream output) throws IOException { - byte[] buffer = new byte[4]; - input.readFully(buffer); - String encodedLength = new String(buffer, StandardCharsets.UTF_8); - int length = Integer.parseInt(encodedLength, 16); - - buffer = new byte[length]; - input.readFully(buffer); - String command = new String(buffer, StandardCharsets.UTF_8); - + String command = readCommand(input); responder.onCommand(command); try { @@ -136,12 +128,21 @@ class AdbProtocolHandler implements Runnable { return Integer.reverseBytes(input.readInt()); } + private int readHexInt(DataInput input) throws IOException { + return Integer.parseInt(readString(input, 4), 16); + } + private String readString(DataInput input, int length) throws IOException { byte[] responseBuffer = new byte[length]; input.readFully(responseBuffer); return new String(responseBuffer, StandardCharsets.UTF_8); } + private String readCommand(DataInput input) throws IOException { + int length = readHexInt(input); + return readString(input, length); + } + private void sync(DataOutput output, DataInput input) throws IOException, JadbException { String id = readString(input, 4); int length = readInt(input); From f679f387eb93d920f28ee7c3646cd40a9418953c Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 13:16:50 +0200 Subject: [PATCH 5/6] AdbProtocolHandler: extract command handlers to separate methods --- .../jadb/server/AdbProtocolHandler.java | 156 +++++++++++------- 1 file changed, 96 insertions(+), 60 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index 1c1621d..7251d3e 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -53,24 +53,13 @@ class AdbProtocolHandler implements Runnable { try { if ("host:version".equals(command)) { - output.writeBytes("OKAY"); - send(output, String.format("%04x", responder.getVersion())); + hostVersion(output); } else if ("host:transport-any".equals(command)) { - // TODO: Check so that exactly one device is selected. - selected = responder.getDevices().get(0); - output.writeBytes("OKAY"); + hostTransportAny(output); } else if ("host:devices".equals(command)) { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - DataOutputStream writer = new DataOutputStream(tmp); - for (AdbDeviceResponder d : responder.getDevices()) { - writer.writeBytes(d.getSerial() + "\t" + d.getType() + "\n"); - } - output.writeBytes("OKAY"); - send(output, new String(tmp.toByteArray(), StandardCharsets.UTF_8)); + hostDevices(output); } else if (command.startsWith("host:transport:")) { - String serial = command.substring("host:transport:".length()); - selected = findDevice(serial); - output.writeBytes("OKAY"); + hostTransport(output, command); } else if ("sync:".equals(command)) { output.writeBytes("OKAY"); try { @@ -80,35 +69,12 @@ class AdbProtocolHandler implements Runnable { sync.send("FAIL", e.getMessage()); } } else if (command.startsWith("shell:")) { - String shellCommand = command.substring("shell:".length()); - output.writeBytes("OKAY"); - shell(shellCommand, output, input); + shell(input, output, command); return false; } else if ("host:get-state".equals(command)) { - // TODO: Check so that exactly one device is selected. - AdbDeviceResponder device = responder.getDevices().get(0); - output.writeBytes("OKAY"); - send(output, device.getType()); + hostGetState(output); } else if (command.startsWith("host-serial:")) { - String[] strs = command.split(":",0); - if (strs.length != 3) { - throw new ProtocolException("Invalid command: " + command); - } - - String serial = strs[1]; - boolean found = false; - output.writeBytes("OKAY"); - for (AdbDeviceResponder d : responder.getDevices()) { - if (d.getSerial().equals(serial)) { - send(output, d.getType()); - found = true; - break; - } - } - - if (!found) { - send(output, "unknown"); - } + hostSerial(output, command); } else { throw new ProtocolException("Unknown command: " + command); } @@ -120,6 +86,68 @@ class AdbProtocolHandler implements Runnable { return true; } + private void hostSerial(DataOutputStream output, String command) throws IOException { + String[] strs = command.split(":",0); + if (strs.length != 3) { + throw new ProtocolException("Invalid command: " + command); + } + + String serial = strs[1]; + boolean found = false; + output.writeBytes("OKAY"); + for (AdbDeviceResponder d : responder.getDevices()) { + if (d.getSerial().equals(serial)) { + send(output, d.getType()); + found = true; + break; + } + } + + if (!found) { + send(output, "unknown"); + } + } + + private void hostGetState(DataOutputStream output) throws IOException { + // TODO: Check so that exactly one device is selected. + AdbDeviceResponder device = responder.getDevices().get(0); + output.writeBytes("OKAY"); + send(output, device.getType()); + } + + private void shell(DataInput input, DataOutputStream output, String command) throws IOException { + String shellCommand = command.substring("shell:".length()); + output.writeBytes("OKAY"); + shell(shellCommand, output, input); + } + + private void hostTransport(DataOutputStream output, String command) throws IOException { + String serial = command.substring("host:transport:".length()); + selected = findDevice(serial); + output.writeBytes("OKAY"); + } + + private void hostDevices(DataOutputStream output) throws IOException { + ByteArrayOutputStream tmp = new ByteArrayOutputStream(); + DataOutputStream writer = new DataOutputStream(tmp); + for (AdbDeviceResponder d : responder.getDevices()) { + writer.writeBytes(d.getSerial() + "\t" + d.getType() + "\n"); + } + output.writeBytes("OKAY"); + send(output, new String(tmp.toByteArray(), StandardCharsets.UTF_8)); + } + + private void hostTransportAny(DataOutputStream output) throws IOException { + // TODO: Check so that exactly one device is selected. + selected = responder.getDevices().get(0); + output.writeBytes("OKAY"); + } + + private void hostVersion(DataOutputStream output) throws IOException { + output.writeBytes("OKAY"); + send(output, String.format("%04x", responder.getVersion())); + } + private void shell(String command, DataOutputStream stdout, DataInput stdin) throws IOException { selected.shell(command, stdout, stdin); } @@ -147,29 +175,37 @@ class AdbProtocolHandler implements Runnable { String id = readString(input, 4); int length = readInt(input); if ("SEND".equals(id)) { - String remotePath = readString(input, length); - int idx = remotePath.lastIndexOf(','); - String path = remotePath; - int mode = 0666; - if (idx > 0) { - path = remotePath.substring(0, idx); - mode = Integer.parseInt(remotePath.substring(idx + 1)); - } - SyncTransport transport = getSyncTransport(output, input); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - transport.readChunksTo(buffer); - selected.filePushed(new RemoteFile(path), mode, buffer); - transport.sendStatus("OKAY", 0); // 0 = ignored + syncSend(output, input, length); } else if ("RECV".equals(id)) { - String remotePath = readString(input, length); - SyncTransport transport = getSyncTransport(output, input); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - selected.filePulled(new RemoteFile(remotePath), buffer); - transport.sendStream(new ByteArrayInputStream(buffer.toByteArray())); - transport.sendStatus("DONE", 0); // ignored + syncRecv(output, input, length); } else throw new JadbException("Unknown sync id " + id); } + private void syncRecv(DataOutput output, DataInput input, int length) throws IOException, JadbException { + String remotePath = readString(input, length); + SyncTransport transport = getSyncTransport(output, input); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + selected.filePulled(new RemoteFile(remotePath), buffer); + transport.sendStream(new ByteArrayInputStream(buffer.toByteArray())); + transport.sendStatus("DONE", 0); // ignored + } + + private void syncSend(DataOutput output, DataInput input, int length) throws IOException, JadbException { + String remotePath = readString(input, length); + int idx = remotePath.lastIndexOf(','); + String path = remotePath; + int mode = 0666; + if (idx > 0) { + path = remotePath.substring(0, idx); + mode = Integer.parseInt(remotePath.substring(idx + 1)); + } + SyncTransport transport = getSyncTransport(output, input); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + transport.readChunksTo(buffer); + selected.filePushed(new RemoteFile(path), mode, buffer); + transport.sendStatus("OKAY", 0); // 0 = ignored + } + private String getCommandLength(String command) { return String.format("%04x", command.length()); } From 063d7ec1cb8f2e6ad5954f604fbd545300e72b7f Mon Sep 17 00:00:00 2001 From: Jano Svitok Date: Wed, 4 Jul 2018 13:20:04 +0200 Subject: [PATCH 6/6] AdbProtocolHandler: move try-catch block to sync method --- .../jadb/server/AdbProtocolHandler.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/se/vidstige/jadb/server/AdbProtocolHandler.java b/src/se/vidstige/jadb/server/AdbProtocolHandler.java index 7251d3e..884112b 100644 --- a/src/se/vidstige/jadb/server/AdbProtocolHandler.java +++ b/src/se/vidstige/jadb/server/AdbProtocolHandler.java @@ -61,13 +61,7 @@ class AdbProtocolHandler implements Runnable { } else if (command.startsWith("host:transport:")) { hostTransport(output, command); } else if ("sync:".equals(command)) { - output.writeBytes("OKAY"); - try { - sync(output, input); - } catch (JadbException e) { // sync response with a different type of fail message - SyncTransport sync = getSyncTransport(output, input); - sync.send("FAIL", e.getMessage()); - } + sync(output, input); } else if (command.startsWith("shell:")) { shell(input, output, command); return false; @@ -171,14 +165,20 @@ class AdbProtocolHandler implements Runnable { return readString(input, length); } - private void sync(DataOutput output, DataInput input) throws IOException, JadbException { - String id = readString(input, 4); - int length = readInt(input); - if ("SEND".equals(id)) { - syncSend(output, input, length); - } else if ("RECV".equals(id)) { - syncRecv(output, input, length); - } else throw new JadbException("Unknown sync id " + id); + private void sync(DataOutput output, DataInput input) throws IOException { + output.writeBytes("OKAY"); + try { + String id = readString(input, 4); + int length = readInt(input); + if ("SEND".equals(id)) { + syncSend(output, input, length); + } else if ("RECV".equals(id)) { + syncRecv(output, input, length); + } else throw new JadbException("Unknown sync id " + id); + } catch (JadbException e) { // sync response with a different type of fail message + SyncTransport sync = getSyncTransport(output, input); + sync.send("FAIL", e.getMessage()); + } } private void syncRecv(DataOutput output, DataInput input, int length) throws IOException, JadbException {