diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/ArtAdapter.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/ArtAdapter.java index b1552ab21..d68b57956 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/ArtAdapter.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/ArtAdapter.java @@ -2,7 +2,7 @@ package jadx.gui.device.debugger; public class ArtAdapter { - public interface Debugger { + public interface IArtAdapter { int getRuntimeRegNum(int smaliNum, int regCount, int paramStart); boolean readNullObject(); @@ -10,7 +10,7 @@ public class ArtAdapter { String typeForNull(); } - public static Debugger getAdapter(int androidReleaseVer) { + public static IArtAdapter getAdapter(int androidReleaseVer) { if (androidReleaseVer <= 8) { return new AndroidOreoAndBelow(); } else { @@ -18,7 +18,7 @@ public class ArtAdapter { } } - public static class AndroidOreoAndBelow implements Debugger { + public static class AndroidOreoAndBelow implements IArtAdapter { @Override public int getRuntimeRegNum(int smaliNum, int regCount, int paramStart) { int localRegCount = regCount - paramStart; @@ -36,7 +36,7 @@ public class ArtAdapter { } } - public static class AndroidPieAndAbove implements Debugger { + public static class AndroidPieAndAbove implements IArtAdapter { @Override public int getRuntimeRegNum(int smaliNum, int regCount, int paramStart) { return smaliNum; diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugController.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugController.java index 129b4a91c..e28f30637 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugController.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugController.java @@ -52,7 +52,7 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe private JDebuggerPanel debuggerPanel; private SmaliDebugger debugger; - private ArtAdapter.Debugger art; + private ArtAdapter.IArtAdapter art; private final CurrentInfo cur = new CurrentInfo(); private BreakpointStore bpStore; @@ -409,7 +409,7 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe for (RegisterObserver.Info info : list) { RegTreeNode reg = cur.frame.getRegNodes().get(info.getSmaliRegNum()); if (info.isLoad()) { - applyDbgInfo(reg, info.getInfo()); + applyDbgInfo(reg, info.getName(), info.getType()); } else { reg.setAlias(""); reg.setAbsoluteType(false); @@ -552,7 +552,7 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe } catch (SmaliDebuggerException e) { logErr(e); } - if (frames.size() == 0) { + if (frames.isEmpty()) { return null; } List frameEleList = new ArrayList<>(frames.size()); @@ -671,7 +671,7 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe private void fetchAllRegisters(FrameNode frame) { List regs = cur.regAdapter.getInitializedList(frame.getCodeOffset()); for (SmaliRegister reg : regs) { - Entry info = cur.regAdapter.getInfo(reg.getRuntimeRegNum(), frame.getCodeOffset()); + RuntimeVarInfo info = cur.regAdapter.getInfo(reg.getRuntimeRegNum(), frame.getCodeOffset()); RegTreeNode regNode = frame.getRegNodes().get(reg.getRegNum()); if (info != null) { applyDbgInfo(regNode, info); @@ -680,9 +680,13 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe } } - private void applyDbgInfo(RegTreeNode rn, Entry info) { - rn.setAlias(info.getKey()); - rn.updateType(info.getValue()); + private void applyDbgInfo(RegTreeNode rn, RuntimeVarInfo info) { + applyDbgInfo(rn, info.getName(), info.getType()); + } + + private void applyDbgInfo(RegTreeNode rn, String alias, String type) { + rn.setAlias(alias); + rn.updateType(type); rn.setAbsoluteType(true); } @@ -877,7 +881,9 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe cur.regAdapter = regAdaMap.computeIfAbsent(cur.mthFullID, k -> RegisterObserver.merge( getRuntimeDebugInfo(cur.frame), - getRegisterList())); + getSmaliRegisterList(), + art, + cur.mthFullID)); if (cur.smali.getRegCount(cur.mthFullID) > 0) { updateAllRegisters(cur.frame); @@ -889,7 +895,7 @@ public final class DebugController implements SmaliDebugger.SuspendListener, IDe }); } - private List getRegisterList() { + private List getSmaliRegisterList() { int regCount = cur.smali.getRegCount(cur.mthFullID); int paramStart = cur.smali.getParamRegStart(cur.mthFullID); List srs = cur.smali.getRegisterList(cur.mthFullID); diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugSettings.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugSettings.java new file mode 100644 index 000000000..c16d9ffa3 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/DebugSettings.java @@ -0,0 +1,158 @@ +package jadx.gui.device.debugger; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jadx.core.utils.StringUtils; +import jadx.gui.device.protocol.ADB; +import jadx.gui.device.protocol.ADBDevice; +import jadx.gui.utils.NLS; + +public class DebugSettings { + private static final Logger LOG = LoggerFactory.getLogger(DebugSettings.class); + + private static final int FORWARD_TCP_PORT = 33233; + + public static final DebugSettings INSTANCE = new DebugSettings(); + + private int ver; + private String pid; + private String name; + private ADBDevice device; + private int forwardTcpPort = FORWARD_TCP_PORT; + private String expectPkg = ""; + private boolean autoAttachPkg = false; + + private DebugSettings() { + } + + public void set(ADBDevice device, int ver, String pid, String name) { + this.ver = ver; + this.pid = pid; + this.name = name; + this.device = device; + this.autoAttachPkg = false; + this.expectPkg = ""; + } + + public DebugSettings setPid(String pid) { + this.pid = pid; + return this; + } + + public DebugSettings setName(String name) { + this.name = name; + return this; + } + + public String forwardJDWP() { + int localPort = forwardTcpPort; + String resultDesc = ""; + try { + do { + ADBDevice.ForwardResult rst = device.forwardJDWP(localPort + "", pid); + if (rst.state == 0) { + forwardTcpPort = localPort; + return ""; + } + if (rst.state == 1) { + if (rst.desc.contains("Only one usage of each socket address")) { // port is taken by other process + if (localPort < 65536) { + localPort++; // retry + continue; + } + } + } + resultDesc = rst.desc; + break; + } while (true); + } catch (Exception e) { + LOG.error("JDWP forward error", e); + } + if (StringUtils.isEmpty(resultDesc)) { + resultDesc = NLS.str("adb_dialog.forward_fail"); + } + return resultDesc; + } + + // we have to remove all ports that forwarding the jdwp:pid, otherwise our JDWP handshake may fail. + public void clearForward() { + String jdwpPid = " jdwp:" + pid; + String tcpPort = " tcp:" + forwardTcpPort; + try { + 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+"); + for (String field : fields) { + if (field.startsWith("tcp:")) { + try { + device.removeForward(field.substring("tcp:".length())); + } catch (Exception e) { + LOG.error("JDWP remove forward error", e); + } + } + } + } + } + } catch (Exception e) { + LOG.error("JDWP clear forward error", e); + } + } + + public boolean isBeingDebugged() { + String jdwpPid = " jdwp:" + pid; + String tcpPort = " tcp:" + forwardTcpPort; + try { + 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); + } + } + } catch (Exception e) { + LOG.error("ADB list forward error", e); + } + return false; + } + + public int getVer() { + return ver; + } + + public String getPid() { + return pid; + } + + public String getName() { + return name; + } + + public ADBDevice getDevice() { + return device; + } + + public int getForwardTcpPort() { + return forwardTcpPort; + } + + public String getExpectPkg() { + return expectPkg; + } + + public void setExpectPkg(String expectPkg) { + this.expectPkg = expectPkg; + } + + public boolean isAutoAttachPkg() { + return autoAttachPkg; + } + + public void setAutoAttachPkg(boolean autoAttachPkg) { + this.autoAttachPkg = autoAttachPkg; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/RegisterObserver.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/RegisterObserver.java index 3b1d2abc7..848abdebf 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/RegisterObserver.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/RegisterObserver.java @@ -1,48 +1,50 @@ package jadx.gui.device.debugger; -import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import io.reactivex.annotations.Nullable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import jadx.core.dex.instructions.args.ArgType; import jadx.gui.device.debugger.SmaliDebugger.RuntimeVarInfo; -import jadx.gui.device.debugger.smali.RegisterInfo; import jadx.gui.device.debugger.smali.SmaliRegister; public class RegisterObserver { private Map> infoMap; - private final List>> regList; + private final List regList; + private final ArtAdapter.IArtAdapter art; + private final String mthFullID; private boolean hasDbgInfo = false; - private RegisterObserver() { - regList = new ArrayList<>(); - infoMap = Collections.emptyMap(); + private RegisterObserver(ArtAdapter.IArtAdapter art, String mthFullID) { + this.regList = new ArrayList<>(); + this.infoMap = Collections.emptyMap(); + this.art = art; + this.mthFullID = mthFullID; } - public static RegisterObserver merge(List rtRegs, List smaliRegs) { - RegisterObserver adapter = new RegisterObserver(); - adapter.hasDbgInfo = rtRegs.size() > 0; + @NotNull + public static RegisterObserver merge(List rtRegs, List smaliRegs, ArtAdapter.IArtAdapter art, + String mthFullID) { + RegisterObserver adapter = new RegisterObserver(art, mthFullID); + adapter.hasDbgInfo = !rtRegs.isEmpty(); if (adapter.hasDbgInfo) { adapter.infoMap = new HashMap<>(); } for (SmaliRegister sr : smaliRegs) { - adapter.regList.add(new SimpleEntry<>(sr, Collections.emptyList())); + adapter.regList.add(new SmaliRegisterMapping(sr)); } - adapter.regList.sort(Comparator.comparingInt(r -> r.getKey().getRuntimeRegNum())); + adapter.regList.sort(Comparator.comparingInt(r -> r.getSmaliRegister().getRuntimeRegNum())); for (RuntimeVarInfo rt : rtRegs) { - Entry> entry = adapter.regList.get(rt.getRegNum()); - if (entry.getValue().isEmpty()) { - entry.setValue(new ArrayList<>()); - } - entry.getValue().add(rt); + final SmaliRegisterMapping smaliRegMapping = adapter.getRegListEntry(rt.getRegNum()); + final SmaliRegister smaliReg = smaliRegMapping.getSmaliRegister(); + smaliRegMapping.addRuntimeVarInfo(rt); String type = rt.getSignature(); if (type.isEmpty()) { @@ -52,9 +54,8 @@ public class RegisterObserver { if (at != null) { type = at.toString(); } - Info load = new Info(entry.getKey().getRegNum(), true, - new SimpleEntry<>(rt.getName(), type)); - Info unload = new Info(entry.getKey().getRegNum(), false, null); + Info load = new Info(smaliReg.getRegNum(), true, rt.getName(), type); + Info unload = new Info(smaliReg.getRegNum(), false, null, null); adapter.infoMap.computeIfAbsent((long) rt.getStartOffset(), k -> new ArrayList<>()) .add(load); adapter.infoMap.computeIfAbsent((long) rt.getEndOffset(), k -> new ArrayList<>()) @@ -63,33 +64,53 @@ public class RegisterObserver { return adapter; } + @NotNull public List getInitializedList(long codeOffset) { List ret = Collections.emptyList(); - for (Entry> info : regList) { - if (info.getKey().isInitialized(codeOffset)) { + for (SmaliRegisterMapping smaliRegisterMapping : regList) { + if (smaliRegisterMapping.getSmaliRegister().isInitialized(codeOffset)) { if (ret.isEmpty()) { ret = new ArrayList<>(); } - ret.add(info.getKey()); + ret.add(smaliRegisterMapping.getSmaliRegister()); } } return ret; } @Nullable - public Entry getInfo(int runtimeNum, long codeOffset) { - Entry> list = regList.get(runtimeNum); - for (RegisterInfo info : list.getValue()) { + public RuntimeVarInfo getInfo(int runtimeNum, long codeOffset) { + SmaliRegisterMapping list = getRegListEntry(runtimeNum); + for (RuntimeVarInfo info : list.getRuntimeVarInfoList()) { if (info.getStartOffset() > codeOffset) { break; } if (info.isInitialized(codeOffset)) { - return new SimpleEntry<>(info.getName(), info.getType()); + return info; } } return null; } + private SmaliRegisterMapping getRegListEntry(int regNum) { + try { + return regList.get(regNum); + } catch (IndexOutOfBoundsException e) { + throw new RuntimeException( + String.format("Register %d does not exist (size: %d).\n %s\n Method: %s", + regNum, regList.size(), buildDeviceInfo(), mthFullID), + e); + } + } + + private String buildDeviceInfo() { + DebugSettings debugSettings = DebugSettings.INSTANCE; + return "Device: " + debugSettings.getDevice().getDeviceInfo() + + ", Android: " + debugSettings.getVer() + + ", ArtAdapter: " + art.getClass().getSimpleName(); + } + + @NotNull public List getInfoAt(long codeOffset) { if (hasDbgInfo) { List list = infoMap.get(codeOffset); @@ -100,15 +121,43 @@ public class RegisterObserver { return Collections.emptyList(); } + public static class SmaliRegisterMapping { + private final SmaliRegister smaliRegister; + + private List rtList = Collections.emptyList(); + + public SmaliRegisterMapping(SmaliRegister smaliRegister) { + this.smaliRegister = smaliRegister; + } + + public SmaliRegister getSmaliRegister() { + return smaliRegister; + } + + @NotNull + public List getRuntimeVarInfoList() { + return rtList; + } + + public void addRuntimeVarInfo(RuntimeVarInfo rt) { + if (rtList.isEmpty()) { + rtList = new ArrayList<>(); + } + rtList.add(rt); + } + } + public static class Info { private final int smaliRegNum; private final boolean load; - private final Entry info; + private final String name; + private final String type; - private Info(int smaliRegNum, boolean load, Entry info) { + private Info(int smaliRegNum, boolean load, String name, String type) { this.smaliRegNum = smaliRegNum; this.load = load; - this.info = info; + this.name = name; + this.type = type; } public int getSmaliRegNum() { @@ -119,8 +168,12 @@ public class RegisterObserver { return load; } - public Entry getInfo() { - return info; + public String getName() { + return name; + } + + public String getType() { + return type; } } } diff --git a/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java b/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java index 9f529465a..f49f0b517 100644 --- a/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java +++ b/jadx-gui/src/main/java/jadx/gui/device/debugger/SmaliDebugger.java @@ -17,6 +17,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.atomic.AtomicInteger; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +72,6 @@ import io.github.skylot.jdwp.JDWP.VirtualMachine.AllClassesWithGeneric.AllClasse import io.github.skylot.jdwp.JDWP.VirtualMachine.AllThreads.AllThreadsReplyData; import io.github.skylot.jdwp.JDWP.VirtualMachine.AllThreads.AllThreadsReplyDataThreads; import io.github.skylot.jdwp.JDWP.VirtualMachine.CreateString.CreateStringReplyData; -import io.reactivex.annotations.NonNull; import jadx.api.plugins.input.data.AccessFlags; import jadx.gui.device.debugger.smali.RegisterInfo; @@ -1292,7 +1292,7 @@ public class SmaliDebugger { return gen; } - @NonNull + @NotNull @Override public String getSignature() { return this.slot.genericSignature.trim(); 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 c3eff1764..9ce1f9020 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 @@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.device.debugger.DbgUtils; +import jadx.gui.device.debugger.DebugSettings; import jadx.gui.device.protocol.ADB; import jadx.gui.device.protocol.ADBDevice; import jadx.gui.device.protocol.ADBDeviceInfo; @@ -51,15 +52,12 @@ import jadx.gui.utils.NLS; import jadx.gui.utils.SystemInfo; import jadx.gui.utils.UiUtils; -import static jadx.gui.device.protocol.ADBDevice.ForwardResult; - public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.JDWPProcessListener { private static final Logger LOG = LoggerFactory.getLogger(ADBDialog.class); private static final long serialVersionUID = -1111111202102181630L; private static final ImageIcon ICON_DEVICE = UiUtils.openSvgIcon("adb/androidDevice"); private static final ImageIcon ICON_PROCESS = UiUtils.openSvgIcon("adb/addToWatch"); - private static DebugSetting debugSetter = null; private final transient MainWindow mainWindow; private transient Label tipLabel; @@ -75,15 +73,12 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J public ADBDialog(MainWindow mainWindow) { super(mainWindow); this.mainWindow = mainWindow; - if (debugSetter == null) { - debugSetter = new DebugSetting(); - } initUI(); pathTextField.setText(mainWindow.getSettings().getAdbDialogPath()); hostTextField.setText(mainWindow.getSettings().getAdbDialogHost()); portTextField.setText(mainWindow.getSettings().getAdbDialogPort()); - if (pathTextField.getText().equals("")) { + if (pathTextField.getText().isEmpty()) { detectADBPath(); } else { pathTextField.setText(""); @@ -329,7 +324,7 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J if (!setupArgs(deviceNode.device, pid, (String) node.getUserObject())) { return; } - if (debugSetter.isBeingDebugged()) { + if (DebugSettings.INSTANCE.isBeingDebugged()) { if (JOptionPane.showConfirmDialog(mainWindow, NLS.str("adb_dialog.being_debugged_msg"), NLS.str("adb_dialog.being_debugged_title"), @@ -347,23 +342,21 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J } private static boolean attachProcess(MainWindow mainWindow) { - if (debugSetter == null) { - return false; - } - debugSetter.clearForward(); - String rst = debugSetter.forwardJDWP(); + DebugSettings debugSettings = DebugSettings.INSTANCE; + debugSettings.clearForward(); + String rst = debugSettings.forwardJDWP(); if (!rst.isEmpty()) { UiUtils.showMessageBox(mainWindow, rst); return false; } try { return mainWindow.getDebuggerPanel().showDebugger( - debugSetter.name, - debugSetter.device.getDeviceInfo().getAdbHost(), - debugSetter.forwardTcpPort, - debugSetter.ver, - debugSetter.device, - debugSetter.pid); + debugSettings.getName(), + debugSettings.getDevice().getDeviceInfo().getAdbHost(), + debugSettings.getForwardTcpPort(), + debugSettings.getVer(), + debugSettings.getDevice(), + debugSettings.getPid()); } catch (Exception e) { LOG.error("Failed to attach to process", e); return false; @@ -371,18 +364,17 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J } public static boolean launchForDebugging(MainWindow mainWindow, String fullAppPath, boolean autoAttach) { - if (debugSetter != null) { - debugSetter.autoAttachPkg = autoAttach; - try { - int pid = debugSetter.device.launchApp(fullAppPath); - if (pid != -1) { - debugSetter.setPid(String.valueOf(pid)) - .setName(fullAppPath); - return attachProcess(mainWindow); - } - } catch (Exception e) { - LOG.error("Failed to launch app", e); + DebugSettings debugSettings = DebugSettings.INSTANCE; + debugSettings.setAutoAttachPkg(autoAttach); + try { + int pid = debugSettings.getDevice().launchApp(fullAppPath); + if (pid != -1) { + debugSettings.setPid(String.valueOf(pid)) + .setName(fullAppPath); + return attachProcess(mainWindow); } + } catch (Exception e) { + LOG.error("Failed to launch app", e); } return false; } @@ -458,7 +450,7 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J procs = Collections.emptyList(); } List procList = new ArrayList<>(id.size()); - if (procs.size() == 0) { + if (procs.isEmpty()) { procList.addAll(id); } else { for (ADB.Process proc : procs) { @@ -479,12 +471,13 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J SwingUtilities.invokeLater(() -> { node.tNode.removeAllChildren(); DefaultMutableTreeNode foundNode = null; + DebugSettings debugSettings = DebugSettings.INSTANCE; for (String procStr : procList) { DefaultMutableTreeNode pnode = new DefaultMutableTreeNode(procStr); node.tNode.add(pnode); - if (!debugSetter.expectPkg.isEmpty() && procStr.endsWith(debugSetter.expectPkg)) { - if (debugSetter.autoAttachPkg && debugSetter.device.equals(node.device)) { - debugSetter.set(node.device, debugSetter.ver, getPid(procStr), procStr); + if (!debugSettings.getExpectPkg().isEmpty() && procStr.endsWith(debugSettings.getExpectPkg())) { + if (debugSettings.isAutoAttachPkg() && debugSettings.getDevice().equals(node.device)) { + debugSettings.set(node.device, debugSettings.getVer(), getPid(procStr), procStr); if (attachProcess(mainWindow)) { dispose(); return; @@ -504,7 +497,7 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J } private void launchApp() { - if (deviceNodes.size() == 0) { + if (deviceNodes.isEmpty()) { UiUtils.showMessageBox(mainWindow, NLS.str("adb_dialog.no_devices")); return; } @@ -533,13 +526,13 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J if (pkg.isEmpty()) { return false; } - debugSetter.expectPkg = " " + pkg; + DebugSettings.INSTANCE.setExpectPkg(" " + pkg); for (int i = 0; i < procTreeRoot.getChildCount(); i++) { DefaultMutableTreeNode rn = (DefaultMutableTreeNode) procTreeRoot.getChildAt(i); for (int j = 0; j < rn.getChildCount(); j++) { DefaultMutableTreeNode n = (DefaultMutableTreeNode) rn.getChildAt(j); String pName = (String) n.getUserObject(); - if (pName.endsWith(debugSetter.expectPkg)) { + if (pName.endsWith(DebugSettings.INSTANCE.getExpectPkg())) { TreePath path = new TreePath(n.getPath()); procTree.scrollPathToVisible(path); procTree.setSelectionPath(path); @@ -594,7 +587,7 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J ver = "8"; } ver = getMajorVer(ver); - debugSetter.set(device, Integer.parseInt(ver), pid, name); + DebugSettings.INSTANCE.set(device, Integer.parseInt(ver), pid, name); return true; } @@ -605,107 +598,4 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J } return ver; } - - private class DebugSetting { - private static final int FORWARD_TCP_PORT = 33233; - private int ver; - private String pid; - private String name; - private ADBDevice device; - private int forwardTcpPort = FORWARD_TCP_PORT; - private String expectPkg = ""; - private boolean autoAttachPkg = false; - - private void set(ADBDevice device, int ver, String pid, String name) { - this.ver = ver; - this.pid = pid; - this.name = name; - this.device = device; - this.autoAttachPkg = false; - this.expectPkg = ""; - } - - private DebugSetting setPid(String pid) { - this.pid = pid; - return this; - } - - private DebugSetting setName(String name) { - this.name = name; - return this; - } - - private String forwardJDWP() { - int localPort = forwardTcpPort; - String resultDesc = ""; - try { - do { - ForwardResult rst = device.forwardJDWP(localPort + "", pid); - if (rst.state == 0) { - forwardTcpPort = localPort; - return ""; - } - if (rst.state == 1) { - if (rst.desc.contains("Only one usage of each socket address")) { // port is taken by other process - if (localPort < 65536) { - localPort++; // retry - continue; - } - } - } - resultDesc = rst.desc; - break; - } while (true); - } catch (Exception e) { - LOG.error("JDWP forward error", e); - } - if (StringUtils.isEmpty(resultDesc)) { - resultDesc = NLS.str("adb_dialog.forward_fail"); - } - return resultDesc; - } - - // we have to remove all ports that forwarding the jdwp:pid, otherwise our JDWP handshake may fail. - private void clearForward() { - String jdwpPid = " jdwp:" + pid; - String tcpPort = " tcp:" + forwardTcpPort; - try { - 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+"); - for (String field : fields) { - if (field.startsWith("tcp:")) { - try { - device.removeForward(field.substring("tcp:".length())); - } catch (Exception e) { - LOG.error("JDWP remove forward error", e); - } - } - } - } - } - } catch (Exception e) { - LOG.error("JDWP clear forward error", e); - } - } - - private boolean isBeingDebugged() { - String jdwpPid = " jdwp:" + pid; - String tcpPort = " tcp:" + forwardTcpPort; - try { - 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); - } - } - } catch (Exception e) { - LOG.error("ADB list forward error", e); - } - return false; - } - } }