fix(gui): use UI thread for adding logcat messages (#2811)
* fix(gui): use UI thread for adding logcat messages other minor/logging improvements for debugger and adb connection * checkstyle
This commit is contained in:
@@ -9,16 +9,18 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class LogUtils {
|
||||
|
||||
private static final Pattern ALFA_NUMERIC = Pattern.compile("\\w*");
|
||||
/**
|
||||
* We replace everything except alphanumeric characters, underscore, dots, colon, semicolon, comma,
|
||||
* spaces, minus
|
||||
*/
|
||||
private static final Pattern REPLACE_PATTERN = Pattern.compile("[^\\w\\.:;, -]");
|
||||
|
||||
public static String escape(String input) {
|
||||
if (input == null) {
|
||||
return "null";
|
||||
}
|
||||
if (ALFA_NUMERIC.matcher(input).matches()) {
|
||||
return input;
|
||||
}
|
||||
return input.replaceAll("\\W", ".");
|
||||
|
||||
return REPLACE_PATTERN.matcher(input).replaceAll(".");
|
||||
}
|
||||
|
||||
public static String escape(byte[] input) {
|
||||
|
||||
@@ -8,6 +8,8 @@ class LogUtilsTest {
|
||||
|
||||
@Test
|
||||
void escape() {
|
||||
assertThat(LogUtils.escape("Guest'%0AUser:'Admin")).isEqualTo("Guest..0AUser..Admin");
|
||||
String src = "a.b,c:d;e disallowed\"a'b#c*d\te\rf\ng";
|
||||
String out = "a.b,c:d;e disallowed.a.b.c.d.e.f.g";
|
||||
assertThat(LogUtils.escape(src)).isEqualTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -26,7 +28,7 @@ public class LogcatController {
|
||||
private final String timezone;
|
||||
private LogcatInfo recent = null;
|
||||
private List<LogcatInfo> events = new ArrayList<>();
|
||||
private LogcatFilter filter = new LogcatFilter(null, null);
|
||||
private LogcatFilter filter = new LogcatFilter();
|
||||
private String status = "null";
|
||||
|
||||
public LogcatController(LogcatPanel logcatPanel, ADBDevice adbDevice) throws IOException {
|
||||
@@ -155,7 +157,7 @@ public class LogcatController {
|
||||
|
||||
public void exit() {
|
||||
stopLogcat();
|
||||
filter = new LogcatFilter(null, null);
|
||||
filter = new LogcatFilter();
|
||||
recent = null;
|
||||
}
|
||||
|
||||
@@ -164,44 +166,25 @@ public class LogcatController {
|
||||
}
|
||||
|
||||
public class LogcatFilter {
|
||||
private final List<Integer> pid;
|
||||
private List<Byte> msgType = new ArrayList<>() {
|
||||
{
|
||||
add((byte) 1);
|
||||
add((byte) 2);
|
||||
add((byte) 3);
|
||||
add((byte) 4);
|
||||
add((byte) 5);
|
||||
add((byte) 6);
|
||||
add((byte) 7);
|
||||
add((byte) 8);
|
||||
}
|
||||
};
|
||||
|
||||
public LogcatFilter(ArrayList<Integer> pid, ArrayList<Byte> msgType) {
|
||||
if (pid != null) {
|
||||
this.pid = pid;
|
||||
} else {
|
||||
this.pid = new ArrayList<>();
|
||||
}
|
||||
private final Set<Integer> pid;
|
||||
private final Set<Byte> msgType;
|
||||
|
||||
if (msgType != null) {
|
||||
this.msgType = msgType;
|
||||
}
|
||||
public LogcatFilter() {
|
||||
this(new TreeSet<>(), new TreeSet<>(List.of((byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6, (byte) 7, (byte) 8)));
|
||||
}
|
||||
|
||||
public LogcatFilter(Set<Integer> pid, Set<Byte> msgType) {
|
||||
this.pid = pid;
|
||||
this.msgType = msgType;
|
||||
}
|
||||
|
||||
public void addPid(int pid) {
|
||||
|
||||
if (!this.pid.contains(pid)) {
|
||||
this.pid.add(pid);
|
||||
}
|
||||
this.pid.add(pid);
|
||||
}
|
||||
|
||||
public void removePid(int pid) {
|
||||
int pidPos = this.pid.indexOf(pid);
|
||||
if (pidPos >= 0) {
|
||||
this.pid.remove(pidPos);
|
||||
}
|
||||
this.pid.remove(pid);
|
||||
}
|
||||
|
||||
public void togglePid(int pid, boolean state) {
|
||||
@@ -213,16 +196,11 @@ public class LogcatController {
|
||||
}
|
||||
|
||||
public void addMsgType(byte msgType) {
|
||||
if (!this.msgType.contains(msgType)) {
|
||||
this.msgType.add(msgType);
|
||||
}
|
||||
this.msgType.add(msgType);
|
||||
}
|
||||
|
||||
public void removeMsgType(byte msgType) {
|
||||
int typePos = this.msgType.indexOf(msgType);
|
||||
if (typePos >= 0) {
|
||||
this.msgType.remove(typePos);
|
||||
}
|
||||
this.msgType.remove(msgType);
|
||||
}
|
||||
|
||||
public void toggleMsgType(byte msgType, boolean state) {
|
||||
@@ -234,10 +212,7 @@ public class LogcatController {
|
||||
}
|
||||
|
||||
public boolean doFilter(LogcatInfo inInfo) {
|
||||
if (pid.contains(inInfo.getPid())) {
|
||||
return msgType.contains(inInfo.getMsgType());
|
||||
}
|
||||
return false;
|
||||
return (pid.contains(inInfo.getPid())) && msgType.contains(inInfo.getMsgType());
|
||||
}
|
||||
|
||||
public List<LogcatInfo> getFilteredList(List<LogcatInfo> inInfoList) {
|
||||
|
||||
@@ -6,14 +6,18 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -24,6 +28,9 @@ import jadx.core.utils.log.LogUtils;
|
||||
import jadx.gui.utils.IOUtils;
|
||||
|
||||
public class ADB {
|
||||
|
||||
public static final Charset ADB_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ADB.class);
|
||||
|
||||
private static final int DEFAULT_PORT = 5037;
|
||||
@@ -31,10 +38,10 @@ public class ADB {
|
||||
|
||||
private static final String CMD_FEATURES = "000dhost:features";
|
||||
private static final String CMD_TRACK_DEVICES = "0014host:track-devices-l";
|
||||
private static final byte[] OKAY = "OKAY".getBytes();
|
||||
private static final byte[] FAIL = "FAIL".getBytes();
|
||||
private static final byte[] OKAY = "OKAY".getBytes(ADB_CHARSET);
|
||||
private static final byte[] FAIL = "FAIL".getBytes(ADB_CHARSET);
|
||||
|
||||
static boolean isOkay(InputStream stream) throws IOException {
|
||||
static boolean isOkay(InputStream stream, String command) throws IOException {
|
||||
byte[] buf = IOUtils.readNBytes(stream, 4);
|
||||
if (Arrays.equals(buf, OKAY)) {
|
||||
return true;
|
||||
@@ -45,13 +52,13 @@ public class ADB {
|
||||
// int msgLen = Integer.parseInt(new String(IOUtils.readNBytes(stream, 4)), 16);
|
||||
// byte[] errorMsg = IOUtils.readNBytes(stream, msgLen);
|
||||
// LOG.error("isOkay failed: received error message: {}", new String(errorMsg));
|
||||
LOG.error("isOkay failed");
|
||||
LOG.error("isOkay failed for command: {}", command);
|
||||
return false;
|
||||
}
|
||||
if (buf == null) {
|
||||
throw new IOException("isOkay failed - steam ended");
|
||||
}
|
||||
throw new IOException("isOkay failed - unexpected response " + new String(buf));
|
||||
throw new IOException("isOkay failed - unexpected response " + new String(buf, ADB_CHARSET));
|
||||
}
|
||||
|
||||
public static byte[] exec(String cmd, OutputStream outputStream, InputStream inputStream) throws IOException {
|
||||
@@ -73,13 +80,13 @@ public class ADB {
|
||||
}
|
||||
|
||||
static boolean execCommandAsync(OutputStream outputStream, InputStream inputStream, String cmd) throws IOException {
|
||||
outputStream.write(cmd.getBytes());
|
||||
return isOkay(inputStream);
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
return isOkay(inputStream, "execCommandAsync");
|
||||
}
|
||||
|
||||
private static byte[] execCommandSync(OutputStream outputStream, InputStream inputStream, String cmd) throws IOException {
|
||||
outputStream.write(cmd.getBytes());
|
||||
if (isOkay(inputStream)) {
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
if (isOkay(inputStream, "execCommandSync")) {
|
||||
return readServiceProtocol(inputStream);
|
||||
}
|
||||
return null;
|
||||
@@ -91,7 +98,7 @@ public class ADB {
|
||||
if (buf == null) {
|
||||
return null;
|
||||
}
|
||||
int len = unhex(buf);
|
||||
int len = hexToInt(buf);
|
||||
byte[] result;
|
||||
if (len == 0) {
|
||||
result = new byte[0];
|
||||
@@ -111,13 +118,15 @@ public class ADB {
|
||||
}
|
||||
|
||||
static boolean setSerial(String serial, OutputStream outputStream, InputStream inputStream) throws IOException {
|
||||
checkSerial(serial);
|
||||
LOG.trace("setSerial({})", serial);
|
||||
String setSerialCmd = String.format("host:tport:serial:%s", serial);
|
||||
setSerialCmd = String.format("%04x%s", setSerialCmd.length(), setSerialCmd);
|
||||
outputStream.write(setSerialCmd.getBytes());
|
||||
boolean ok = isOkay(inputStream);
|
||||
outputStream.write(setSerialCmd.getBytes(ADB_CHARSET));
|
||||
boolean ok = isOkay(inputStream, setSerialCmd);
|
||||
if (ok) {
|
||||
// skip the shell-state-id returned by ADB server, it's not important for the following actions.
|
||||
IOUtils.readNBytes(inputStream, 8);
|
||||
inputStream.readNBytes(8);
|
||||
} else {
|
||||
LOG.error("setSerial command {} failed", LogUtils.escape(setSerialCmd));
|
||||
}
|
||||
@@ -127,8 +136,8 @@ public class ADB {
|
||||
private static byte[] execShellCommandRaw(String cmd, OutputStream outputStream, InputStream inputStream) throws IOException {
|
||||
cmd = String.format("shell,v2,TERM=xterm-256color,raw:%s", cmd);
|
||||
cmd = String.format("%04x%s", cmd.length(), cmd);
|
||||
outputStream.write(cmd.getBytes());
|
||||
if (isOkay(inputStream)) {
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
if (isOkay(inputStream, cmd)) {
|
||||
return ShellProtocol.readStdout(inputStream);
|
||||
}
|
||||
return null;
|
||||
@@ -144,7 +153,7 @@ public class ADB {
|
||||
public static List<String> getFeatures() throws IOException {
|
||||
byte[] rst = exec(CMD_FEATURES);
|
||||
if (rst != null) {
|
||||
return Arrays.asList(new String(rst).trim().split(","));
|
||||
return Arrays.asList(new String(rst, ADB_CHARSET).trim().split(","));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -202,7 +211,7 @@ public class ADB {
|
||||
break; // socket disconnected
|
||||
}
|
||||
if (listener != null) {
|
||||
String payload = new String(res);
|
||||
String payload = new String(res, ADB_CHARSET);
|
||||
String[] deviceLines = payload.split("\n");
|
||||
List<ADBDeviceInfo> deviceInfoList = new ArrayList<>(deviceLines.length);
|
||||
for (String deviceLine : deviceLines) {
|
||||
@@ -225,11 +234,11 @@ public class ADB {
|
||||
String cmd = "0011host:list-forward";
|
||||
InputStream inputStream = socket.getInputStream();
|
||||
OutputStream outputStream = socket.getOutputStream();
|
||||
outputStream.write(cmd.getBytes());
|
||||
if (isOkay(inputStream)) {
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
if (isOkay(inputStream, "listForward")) {
|
||||
byte[] bytes = readServiceProtocol(inputStream);
|
||||
if (bytes != null) {
|
||||
String[] forwards = new String(bytes).split("\n");
|
||||
String[] forwards = new String(bytes, ADB_CHARSET).split("\n");
|
||||
return Stream.of(forwards).map(String::trim).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -244,8 +253,8 @@ public class ADB {
|
||||
InputStream inputStream = socket.getInputStream();
|
||||
OutputStream outputStream = socket.getOutputStream();
|
||||
if (setSerial(serial, outputStream, inputStream)) {
|
||||
outputStream.write(cmd.getBytes());
|
||||
return isOkay(inputStream) && isOkay(inputStream);
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
return isOkay(inputStream, "removeForward1") && isOkay(inputStream, "removeForward2");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -267,7 +276,21 @@ public class ADB {
|
||||
return rst;
|
||||
}
|
||||
|
||||
private static int unhex(byte[] hex) {
|
||||
private static final Pattern SERIAL_PATTERN = Pattern.compile("^[\\w-]{10,20}$");
|
||||
|
||||
private static void checkSerial(String serial) {
|
||||
if (!SERIAL_PATTERN.matcher(serial).matches()) {
|
||||
throw new IllegalArgumentException("Invalid serial: " + serial);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 4 hex characters to int
|
||||
*
|
||||
* @param hex
|
||||
* @return
|
||||
*/
|
||||
private static int hexToInt(byte[] hex) {
|
||||
int n = 0;
|
||||
byte b;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -340,6 +363,16 @@ public class ADB {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringJoiner(", ", Process.class.getSimpleName() + "[", "]")
|
||||
.add("user='" + user + "'")
|
||||
.add("pid='" + pid + "'")
|
||||
.add("ppid='" + ppid + "'")
|
||||
.add("name='" + name + "'")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ShellProtocol {
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -21,6 +20,8 @@ import jadx.core.utils.log.LogUtils;
|
||||
import jadx.gui.device.protocol.ADB.JDWPProcessListener;
|
||||
import jadx.gui.device.protocol.ADB.Process;
|
||||
|
||||
import static jadx.gui.device.protocol.ADB.ADB_CHARSET;
|
||||
|
||||
public class ADBDevice {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ADBDevice.class);
|
||||
|
||||
@@ -65,16 +66,16 @@ public class ADBDevice {
|
||||
OutputStream outputStream = socket.getOutputStream();
|
||||
ForwardResult rst;
|
||||
if (ADB.setSerial(info.getSerial(), outputStream, inputStream)) {
|
||||
outputStream.write(cmd.getBytes());
|
||||
if (!ADB.isOkay(inputStream)) {
|
||||
outputStream.write(cmd.getBytes(ADB_CHARSET));
|
||||
if (!ADB.isOkay(inputStream, "forwardJDWP1")) {
|
||||
rst = new ForwardResult(1, ADB.readServiceProtocol(inputStream));
|
||||
} else if (!ADB.isOkay(inputStream)) {
|
||||
} else if (!ADB.isOkay(inputStream, "forwardJDWP2")) {
|
||||
rst = new ForwardResult(2, ADB.readServiceProtocol(inputStream));
|
||||
} else {
|
||||
rst = new ForwardResult(0, null);
|
||||
}
|
||||
} else {
|
||||
rst = new ForwardResult(1, "Unknown error.".getBytes());
|
||||
rst = new ForwardResult(1, "Unknown error.".getBytes(ADB_CHARSET));
|
||||
}
|
||||
return rst;
|
||||
}
|
||||
@@ -89,7 +90,7 @@ public class ADBDevice {
|
||||
|
||||
public ForwardResult(int state, byte[] desc) {
|
||||
if (desc != null) {
|
||||
this.desc = new String(desc);
|
||||
this.desc = new String(desc, ADB_CHARSET);
|
||||
} else {
|
||||
this.desc = "";
|
||||
}
|
||||
@@ -109,7 +110,7 @@ public class ADBDevice {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
String rst = new String(res).trim();
|
||||
String rst = new String(res, ADB_CHARSET).trim();
|
||||
if (rst.startsWith("Starting: Intent {") && rst.endsWith(fullAppName + " }")) {
|
||||
Thread.sleep(40);
|
||||
String pkg = fullAppName.split("/")[0];
|
||||
@@ -124,10 +125,10 @@ public class ADBDevice {
|
||||
* @return binary output of logcat
|
||||
*/
|
||||
public byte[] getBinaryLogcat() throws IOException {
|
||||
|
||||
Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort());
|
||||
String cmd = "logcat -dB";
|
||||
return ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) {
|
||||
String cmd = "logcat -dB";
|
||||
return ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,32 +136,38 @@ public class ADBDevice {
|
||||
* Timestamp is in the format 09-08 02:18:03.131
|
||||
*/
|
||||
public byte[] getBinaryLogcat(String timestamp) throws IOException {
|
||||
Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort());
|
||||
Matcher matcher = TIMESTAMP_FORMAT.matcher(timestamp);
|
||||
if (!matcher.find()) {
|
||||
LOG.error("Invalid Logcat Timestamp " + timestamp);
|
||||
try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) {
|
||||
Matcher matcher = TIMESTAMP_FORMAT.matcher(timestamp);
|
||||
if (!matcher.find()) {
|
||||
LOG.error("Invalid Logcat Timestamp {}", timestamp);
|
||||
}
|
||||
String cmd = "logcat -dB -t \"" + timestamp + "\"";
|
||||
return ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
}
|
||||
String cmd = "logcat -dB -t \"" + timestamp + "\"";
|
||||
return ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary output of logcat -c
|
||||
*/
|
||||
public void clearLogcat() throws IOException {
|
||||
Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort());
|
||||
String cmd = "logcat -c";
|
||||
ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) {
|
||||
String cmd = "logcat -c";
|
||||
ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Timezone for the attached android device
|
||||
*/
|
||||
public String getTimezone() throws IOException {
|
||||
Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort());
|
||||
String cmd = "getprop persist.sys.timezone";
|
||||
byte[] tz = ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
return new String(tz).trim();
|
||||
try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) {
|
||||
String cmd = "getprop persist.sys.timezone";
|
||||
byte[] tz = ADB.execShellCommandRaw(info.getSerial(), cmd, socket.getOutputStream(), socket.getInputStream());
|
||||
if (tz == null) {
|
||||
throw new IOException("Failed to get timezone");
|
||||
}
|
||||
return new String(tz, ADB_CHARSET).trim();
|
||||
}
|
||||
}
|
||||
|
||||
public String getAndroidReleaseVersion() {
|
||||
@@ -169,9 +176,10 @@ public class ADBDevice {
|
||||
}
|
||||
try {
|
||||
List<String> list = getProp("ro.build.version.release");
|
||||
if (list.size() != 0) {
|
||||
androidReleaseVer = list.get(0);
|
||||
if (!list.isEmpty()) {
|
||||
return list.get(0);
|
||||
}
|
||||
LOG.error("Failed to get android release version - no result");
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to get android release version", e);
|
||||
androidReleaseVer = "";
|
||||
@@ -180,6 +188,7 @@ public class ADBDevice {
|
||||
}
|
||||
|
||||
public List<String> getProp(String entry) throws IOException {
|
||||
LOG.debug("ADB getProp({})", entry);
|
||||
try (Socket socket = ADB.connect(info.getAdbHost(), info.getAdbPort())) {
|
||||
List<String> props = Collections.emptyList();
|
||||
String cmd = "getprop";
|
||||
@@ -190,7 +199,7 @@ public class ADBDevice {
|
||||
socket.getOutputStream(), socket.getInputStream());
|
||||
if (payload != null) {
|
||||
props = new ArrayList<>();
|
||||
String[] lines = new String(payload).split("\n");
|
||||
String[] lines = new String(payload, ADB_CHARSET).split("\n");
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
if (!line.isEmpty()) {
|
||||
@@ -198,6 +207,7 @@ public class ADBDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.trace("ADB getProp({}) = {}", entry, props);
|
||||
return props;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +226,8 @@ public class ADBDevice {
|
||||
byte[] payload = ADB.execShellCommandRaw(info.getSerial(), cmd,
|
||||
socket.getOutputStream(), socket.getInputStream());
|
||||
if (payload != null) {
|
||||
String ps = new String(payload);
|
||||
String ps = new String(payload, ADB_CHARSET);
|
||||
// LOG.trace("ADB getProcessList({}) = {}", cmd, ps);
|
||||
String[] psLines = ps.split("\n");
|
||||
for (String line : psLines) {
|
||||
line = line.trim();
|
||||
@@ -244,12 +255,12 @@ public class ADBDevice {
|
||||
OutputStream outputStream = jdwpListenerSock.getOutputStream();
|
||||
if (ADB.setSerial(info.getSerial(), outputStream, inputStream)
|
||||
&& ADB.execCommandAsync(outputStream, inputStream, CMD_TRACK_JDWP)) {
|
||||
Executors.newFixedThreadPool(1).execute(() -> {
|
||||
new Thread(() -> {
|
||||
for (;;) {
|
||||
byte[] res = ADB.readServiceProtocol(inputStream);
|
||||
if (res != null) {
|
||||
if (listener != null) {
|
||||
String payload = new String(res);
|
||||
String payload = new String(res, ADB_CHARSET);
|
||||
String[] ids = payload.split("\n");
|
||||
Set<String> idList = new HashSet<>(ids.length);
|
||||
for (String id : ids) {
|
||||
@@ -257,6 +268,9 @@ public class ADBDevice {
|
||||
idList.add(id);
|
||||
}
|
||||
}
|
||||
if (idList.isEmpty()) {
|
||||
LOG.info("No debuggable app process found on device {}", info.getSerial());
|
||||
}
|
||||
listener.jdwpProcessOccurred(this, idList);
|
||||
}
|
||||
} else { // socket disconnected
|
||||
@@ -267,13 +281,13 @@ public class ADBDevice {
|
||||
this.jdwpListenerSock = null;
|
||||
listener.jdwpListenerClosed(this);
|
||||
}
|
||||
});
|
||||
}).start();
|
||||
return true;
|
||||
} else {
|
||||
jdwpListenerSock.close();
|
||||
jdwpListenerSock = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void stopListenForJDWP() {
|
||||
|
||||
@@ -279,6 +279,7 @@ public class ADBDialog extends JDialog implements ADB.DeviceStateListener, ADB.J
|
||||
|
||||
@Override
|
||||
public void onDeviceStatusChange(List<ADBDeviceInfo> deviceInfoList) {
|
||||
LOG.debug("onDeviceStatusChange {}", deviceInfoList);
|
||||
List<DeviceNode> nodes = new ArrayList<>(deviceInfoList.size());
|
||||
info_loop: for (ADBDeviceInfo info : deviceInfoList) {
|
||||
for (DeviceNode deviceNode : deviceNodes) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
@@ -61,6 +62,10 @@ public class LogcatPanel extends JPanel {
|
||||
private final AttributeSet fatalAset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.decode("#d33682"));
|
||||
private final AttributeSet silentAset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.decode("#002b36"));
|
||||
|
||||
private final Map<Byte, AttributeSet> asetMap =
|
||||
Map.of((byte) 1, defaultAset, (byte) 2, verboseAset, (byte) 3, debugAset, (byte) 4, infoAset, (byte) 5, warningAset,
|
||||
(byte) 6, errorAset, (byte) 7, fatalAset, (byte) 8, silentAset);
|
||||
|
||||
private static final ImageIcon ICON_PAUSE = UiUtils.openSvgIcon("debugger/threadFrozen");
|
||||
private static final ImageIcon ICON_RUN = UiUtils.openSvgIcon("debugger/execute");
|
||||
private static final ImageIcon CLEAR_LOGCAT = UiUtils.openSvgIcon("debugger/trash");
|
||||
@@ -199,64 +204,29 @@ public class LogcatPanel extends JPanel {
|
||||
}
|
||||
|
||||
public void log(LogcatController.LogcatInfo logcatInfo) {
|
||||
boolean atBottom = false;
|
||||
|
||||
int len = logcatPane.getDocument().getLength();
|
||||
JScrollBar scrollbar = logcatScroll.getVerticalScrollBar();
|
||||
if (isAtBottom(scrollbar)) {
|
||||
atBottom = true;
|
||||
boolean atBottom = isAtBottom(scrollbar);
|
||||
|
||||
String logString = " > " + logcatInfo.getTimestamp() + " [pid: " + logcatInfo.getPid() + "] "
|
||||
+ logcatInfo.getMsgTypeString() + ": " + logcatInfo.getMsg() + "\n";
|
||||
|
||||
if (logcatInfo.getMsgType() == 0) {
|
||||
return; // ignore unknown
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(" > ")
|
||||
.append(logcatInfo.getTimestamp())
|
||||
.append(" [pid: ")
|
||||
.append(logcatInfo.getPid())
|
||||
.append("] ")
|
||||
.append(logcatInfo.getMsgTypeString())
|
||||
.append(": ")
|
||||
.append(logcatInfo.getMsg())
|
||||
.append("\n");
|
||||
AttributeSet attrSet = asetMap.get(logcatInfo.getMsgType());
|
||||
|
||||
try {
|
||||
switch (logcatInfo.getMsgType()) {
|
||||
case 0: // Unknown
|
||||
break;
|
||||
case 1: // Default
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), defaultAset);
|
||||
break;
|
||||
case 2: // Verbose
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), verboseAset);
|
||||
break;
|
||||
case 3: // Debug
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), debugAset);
|
||||
break;
|
||||
case 4: // Info
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), infoAset);
|
||||
break;
|
||||
case 5: // Warn
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), warningAset);
|
||||
break;
|
||||
case 6: // Error
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), errorAset);
|
||||
break;
|
||||
case 7: // Fatal
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), fatalAset);
|
||||
break;
|
||||
case 8: // Silent
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), silentAset);
|
||||
break;
|
||||
default:
|
||||
logcatPane.getDocument().insertString(len, sb.toString(), null);
|
||||
break;
|
||||
UiUtils.uiRun(() -> {
|
||||
try {
|
||||
logcatPane.getDocument().insertString(len, logString, attrSet);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to add logcat message", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to write logcat message", e);
|
||||
}
|
||||
|
||||
if (atBottom) {
|
||||
EventQueue.invokeLater(() -> scrollbar.setValue(scrollbar.getMaximum()));
|
||||
}
|
||||
if (atBottom) {
|
||||
EventQueue.invokeLater(() -> scrollbar.setValue(scrollbar.getMaximum()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
@@ -282,7 +252,7 @@ public class LogcatPanel extends JPanel {
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JComboBox cb = (JComboBox) e.getSource();
|
||||
JComboBox<?> cb = (JComboBox<?>) e.getSource();
|
||||
CheckComboStore store = (CheckComboStore) cb.getSelectedItem();
|
||||
CheckComboRenderer ccr = (CheckComboRenderer) cb.getRenderer();
|
||||
store.state = !store.state;
|
||||
@@ -350,11 +320,7 @@ public class LogcatPanel extends JPanel {
|
||||
public void selectAllBut(int ind) {
|
||||
for (int i = 0; i < combo.getItemCount(); i++) {
|
||||
CheckComboStore ccs = combo.getItemAt(i);
|
||||
if (i != ind) {
|
||||
ccs.state = false;
|
||||
} else {
|
||||
ccs.state = true;
|
||||
}
|
||||
ccs.state = (i == ind);
|
||||
switch (type) {
|
||||
case 1: // process
|
||||
logcatController.getFilter().togglePid(ccs.index, ccs.state);
|
||||
|
||||
Reference in New Issue
Block a user