diff --git a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADB.java b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADB.java index 11e21ddca1c..e56b3389330 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADB.java +++ b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADB.java @@ -103,7 +103,7 @@ static byte[] readServiceProtocol(InputStream stream) { } return result; } catch (SocketException e) { - LOG.error("Aborting readServiceProtocol: socket closed"); + LOG.warn("Aborting readServiceProtocol: {}", e.toString()); } catch (IOException e) { LOG.error("Failed to read readServiceProtocol", e); } @@ -207,7 +207,7 @@ public static Socket listenForDeviceState(DeviceStateListener listener, String h List deviceInfoList = new ArrayList<>(deviceLines.length); for (String deviceLine : deviceLines) { if (!deviceLine.trim().isEmpty()) { - deviceInfoList.add(ADBDeviceInfo.make(deviceLine, host, port)); + deviceInfoList.add(new ADBDeviceInfo(deviceLine, host, port)); } } listener.onDeviceStatusChange(deviceInfoList); diff --git a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDevice.java b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDevice.java index 82653c0b61a..8fd44df3aac 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDevice.java +++ b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDevice.java @@ -39,7 +39,10 @@ public ADBDeviceInfo getDeviceInfo() { } public boolean updateDeviceInfo(ADBDeviceInfo info) { - boolean matched = this.info.serial.equals(info.serial); + if (info.getSerial() == null || info.getSerial().isEmpty()) { + return false; + } + boolean matched = this.info.getSerial().equals(info.getSerial()); if (matched) { this.info = info; } @@ -47,21 +50,21 @@ public boolean updateDeviceInfo(ADBDeviceInfo info) { } public String getSerial() { - return info.serial; + return info.getSerial(); } public boolean removeForward(String localPort) throws IOException { - return ADB.removeForward(info.adbHost, info.adbPort, info.serial, localPort); + return ADB.removeForward(info.getAdbHost(), info.getAdbPort(), info.getSerial(), localPort); } public ForwardResult forwardJDWP(String localPort, String jdwpPid) throws IOException { - try (Socket socket = ADB.connect(info.adbHost, info.adbPort)) { + try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) { String cmd = String.format("host:forward:tcp:%s;jdwp:%s", localPort, jdwpPid); cmd = String.format("%04x%s", cmd.length(), cmd); InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); ForwardResult rst; - if (ADB.setSerial(info.serial, outputStream, inputStream)) { + if (ADB.setSerial(info.getSerial(), outputStream, inputStream)) { outputStream.write(cmd.getBytes()); if (!ADB.isOkay(inputStream)) { rst = new ForwardResult(1, ADB.readServiceProtocol(inputStream)); @@ -99,9 +102,9 @@ public ForwardResult(int state, byte[] desc) { */ public int launchApp(String fullAppName) throws IOException, InterruptedException { byte[] res; - try (Socket socket = ADB.connect(info.adbHost, info.adbPort)) { + try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) { String cmd = "am start -D -n " + fullAppName; - res = ADB.execShellCommandRaw(info.serial, cmd, socket.getOutputStream(), socket.getInputStream()); + res = ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream()); if (res == null) { return -1; } @@ -134,13 +137,13 @@ public String getAndroidReleaseVersion() { } public List getProp(String entry) throws IOException { - try (Socket socket = ADB.connect(info.adbHost, info.adbPort)) { + try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) { List props = Collections.emptyList(); String cmd = "getprop"; if (!StringUtils.isEmpty(entry)) { cmd += " " + entry; } - byte[] payload = ADB.execShellCommandRaw(info.serial, cmd, + byte[] payload = ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream()); if (payload != null) { props = new ArrayList<>(); @@ -166,9 +169,9 @@ public List getProcessList() throws IOException { } private List getProcessList(String cmd, int index) throws IOException { - try (Socket socket = ADB.connect(info.adbHost, info.adbPort)) { + try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) { List procs = new ArrayList<>(); - byte[] payload = ADB.execShellCommandRaw(info.serial, cmd, + byte[] payload = ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream()); if (payload != null) { String ps = new String(payload); @@ -194,10 +197,10 @@ public boolean listenForJDWP(JDWPProcessListener listener) throws IOException { if (this.jdwpListenerSock != null) { return false; } - jdwpListenerSock = ADB.connect(this.info.adbHost, this.info.adbPort); + jdwpListenerSock = ADB.connect(this.info.getAdbHost(), this.info.getAdbPort()); InputStream inputStream = jdwpListenerSock.getInputStream(); OutputStream outputStream = jdwpListenerSock.getOutputStream(); - if (ADB.setSerial(info.serial, outputStream, inputStream) + if (ADB.setSerial(info.getSerial(), outputStream, inputStream) && ADB.execCommandAsync(outputStream, inputStream, CMD_TRACK_JDWP)) { Executors.newFixedThreadPool(1).execute(() -> { for (;;) { @@ -244,19 +247,20 @@ public void stopListenForJDWP() { @Override public int hashCode() { - return info.serial.hashCode(); + return info.getSerial().hashCode(); } @Override public boolean equals(Object obj) { if (obj instanceof ADBDevice) { - return ((ADBDevice) obj).getDeviceInfo().serial.equals(info.serial); + String otherSerial = ((ADBDevice) obj).getDeviceInfo().getSerial(); + return otherSerial.equals(info.getSerial()); } return false; } @Override public String toString() { - return info.allInfo; + return info.getAllInfo(); } } diff --git a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDeviceInfo.java b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDeviceInfo.java index b61ae143a80..ba95c387b76 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDeviceInfo.java +++ b/jadx-gui/src/main/java/jadx/gui/device/protocol/ADBDeviceInfo.java @@ -1,42 +1,91 @@ package jadx.gui.device.protocol; +import java.util.Map; +import java.util.TreeMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jadx.core.utils.log.LogUtils; + public class ADBDeviceInfo { - public String adbHost; - public int adbPort; - public String serial; - public String state; - public String model; - public String allInfo; + private static final Logger LOG = LoggerFactory.getLogger(ADBDeviceInfo.class); + private final String adbHost; + private final int adbPort; + private final String serial; + private final String state; + private final String model; + private final String allInfo; + + /** + * Store the device info property values like "device" "model" "product" or "transport_id" + */ + private final Map propertiesMap = new TreeMap<>(); + + ADBDeviceInfo(String info, String host, int port) { + String[] infoFields = info.trim().split("\\s+"); + allInfo = String.join(" ", infoFields); + if (infoFields.length > 2) { + serial = infoFields[0]; + state = infoFields[1]; + + for (int i = 2; i < infoFields.length; i++) { + String field = infoFields[i]; + int idx = field.indexOf(':'); + if (idx > 0) { + String key = field.substring(0, idx); + String value = field.substring(idx + 1); + if (!value.isEmpty()) { + propertiesMap.put(key, value); + } + } + } + model = propertiesMap.getOrDefault("model", serial); + } else { + LOG.error("Unable to extract device information from {}", LogUtils.escape(info)); + serial = ""; + state = "unknown"; + model = "unknown"; + } + adbHost = host; + adbPort = port; + } public boolean isOnline() { return state.equals("device"); } + public String getAdbHost() { + return adbHost; + } + + public int getAdbPort() { + return adbPort; + } + + public String getSerial() { + return serial; + } + + public String getState() { + return state; + } + + public String getModel() { + return model; + } + + public String getAllInfo() { + return allInfo; + } + + public String getProperty(String key) { + return this.propertiesMap.get(key); + } + @Override public String toString() { return allInfo; } - static ADBDeviceInfo make(String info, String host, int port) { - ADBDeviceInfo deviceInfo = new ADBDeviceInfo(); - String[] infoFields = info.trim().split("\\s+"); - deviceInfo.allInfo = String.join(" ", infoFields); - if (infoFields.length > 2) { - deviceInfo.serial = infoFields[0]; - deviceInfo.state = infoFields[1]; - } - int pos = info.indexOf("model:"); - if (pos != -1) { - int spacePos = info.indexOf(" ", pos); - if (spacePos != -1) { - deviceInfo.model = info.substring(pos + "model:".length(), spacePos); - } - } - if (deviceInfo.model == null || deviceInfo.model.equals("")) { - deviceInfo.model = deviceInfo.serial; - } - deviceInfo.adbHost = host; - deviceInfo.adbPort = port; - return deviceInfo; - } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/ADBDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/ADBDialog.java index d9fc4590280..edc3900c519 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/ADBDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/ADBDialog.java @@ -359,7 +359,7 @@ private static boolean attachProcess(MainWindow mainWindow) { try { return mainWindow.getDebuggerPanel().showDebugger( debugSetter.name, - debugSetter.device.getDeviceInfo().adbHost, + debugSetter.device.getDeviceInfo().getAdbHost(), debugSetter.forwardTcpPort, debugSetter.ver); } catch (Exception e) { @@ -569,10 +569,10 @@ private static class DeviceNode { void refresh() { ADBDeviceInfo info = device.getDeviceInfo(); - String text = info.model; + String text = info.getModel(); if (text != null) { - if (!text.equals(info.serial)) { - text += String.format(" [serial: %s]", info.serial); + if (!text.equals(info.getSerial())) { + text += String.format(" [serial: %s]", info.getSerial()); } text += String.format(" [state: %s]", info.isOnline() ? "online" : "offline"); tNode.setUserObject(text); @@ -668,8 +668,8 @@ private void clearForward() { String jdwpPid = " jdwp:" + pid; String tcpPort = " tcp:" + forwardTcpPort; try { - List list = ADB.listForward(device.getDeviceInfo().adbHost, - device.getDeviceInfo().adbPort); + List list = ADB.listForward(device.getDeviceInfo().getAdbHost(), + device.getDeviceInfo().getAdbPort()); for (String s : list) { if (s.startsWith(device.getSerial()) && s.endsWith(jdwpPid) && !s.contains(tcpPort)) { String[] fields = s.split("\\s+"); @@ -693,8 +693,8 @@ private boolean isBeingDebugged() { String jdwpPid = " jdwp:" + pid; String tcpPort = " tcp:" + forwardTcpPort; try { - List list = ADB.listForward(device.getDeviceInfo().adbHost, - device.getDeviceInfo().adbPort); + List list = ADB.listForward(device.getDeviceInfo().getAdbHost(), + device.getDeviceInfo().getAdbPort()); for (String s : list) { if (s.startsWith(device.getSerial()) && s.endsWith(jdwpPid)) { return !s.contains(tcpPort);