From e967f5c25540ac496f4b52e7f44ec61603697d21 Mon Sep 17 00:00:00 2001 From: Eason Xiang Date: Mon, 5 Oct 2026 11:27:20 +0800 Subject: [PATCH] Problem reports from Android 6 carry the app's logcat lines logcat's --pid option is Android 7+. On Android 6 it printed its usage text, and that text was what the report's system log section held (seen in CB-JP2RHT from a Xiaomi TV). There, every process's recent lines are now read and only this process's kept; logcat output that isn't a log line, such as its usage, is always left out. Co-Authored-By: Claude Opus 5.5 --- .../java/com/weenas/castbay/util/LogReport.kt | 24 +++++++++++++++---- .../com/weenas/castbay/util/LogReportTest.kt | 17 +++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/weenas/castbay/util/LogReport.kt b/app/src/main/java/com/weenas/castbay/util/LogReport.kt index c650433..71898df 100644 --- a/app/src/main/java/com/weenas/castbay/util/LogReport.kt +++ b/app/src/main/java/com/weenas/castbay/util/LogReport.kt @@ -146,14 +146,30 @@ object LogReport { /** This process's lines in logcat, oldest first; empty if logcat can't be read. */ private fun logcat(): List = runCatching { - val process = ProcessBuilder( - "logcat", "-d", "-v", "threadtime", "-t", LOGCAT_LINES.toString(), "--pid", Process.myPid().toString() - ).redirectErrorStream(true).start() + val pid = Process.myPid() + // logcat's --pid is Android 7+: Android 6's printed its usage instead. There, every + // process's recent lines are read and this one's kept. + val byPid = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N + val command = mutableListOf("logcat", "-d", "-v", "threadtime", "-t", (if (byPid) LOGCAT_LINES else LOGCAT_LINES * 5).toString()) + if (byPid) command += listOf("--pid", pid.toString()) + val process = ProcessBuilder(command).redirectErrorStream(true).start() val lines = process.inputStream.bufferedReader().use { it.readLines() } process.destroy() - lines + processLines(lines, pid) }.getOrDefault(emptyList()) + /** + * The lines of [pid] in threadtime format ("10-04 15:21:53.785 6213 6256 I Tag: …"); anything + * else, such as logcat's usage or another process's lines, is left out. + */ + internal fun processLines(lines: List, pid: Int): List { + val own = pid.toString() + return lines.filter { line -> + val fields = line.trim().split(Regex("\\s+"), limit = 4) + fields.size == 4 && fields[0].length == 5 && fields[0][2] == '-' && fields[2] == own + } + } + // UxPlay logs the PIN a sender must enter, and the like. private val secret = Regex("""(?i)\b(pin|password|passwd)(\s*[=:]\s*)"[^"]*"""") private val personal = Regex("${Log.PERSONAL_START}[^${Log.PERSONAL_END}\\n]*${Log.PERSONAL_END}") diff --git a/app/src/test/java/com/weenas/castbay/util/LogReportTest.kt b/app/src/test/java/com/weenas/castbay/util/LogReportTest.kt index 4f5b1e7..65807c7 100644 --- a/app/src/test/java/com/weenas/castbay/util/LogReportTest.kt +++ b/app/src/test/java/com/weenas/castbay/util/LogReportTest.kt @@ -48,4 +48,21 @@ class LogReportTest { assertEquals("too many reports", LogReport.reason(LogReport.TooManyReports())) assertEquals("address not found (DNS)", LogReport.reason(java.net.UnknownHostException("castbay.weenas.com"))) } + + @Test + fun keepsOnlyThisProcessesLogcatLines() { + val lines = listOf( + "--------- beginning of main", + "10-04 15:21:53.785 6213 6256 I CastBay: mine", + "10-04 15:21:53.790 2705 3117 D MDnsDS : someone else's", + "10-04 15:21:54.000 6213 6213 W AirPlay: mine too", + "Unrecognized Option -", + "Usage: logcat [options] [filterspecs]", + ) + assertEquals( + listOf("10-04 15:21:53.785 6213 6256 I CastBay: mine", "10-04 15:21:54.000 6213 6213 W AirPlay: mine too"), + LogReport.processLines(lines, 6213) + ) + assertEquals(emptyList(), LogReport.processLines(listOf("Unrecognized Option -", "Usage: logcat"), 6213)) + } }