{"record":{"id":"0340250ab35cba13","repo":"MuntashirAkon/AppManager","slug":"timed-out-waiting-for-adb-command-command","errorCode":null,"errorMessage":"Timed out waiting for ADB command: ${command}","messagePattern":"Timed out waiting for ADB command: (.+?)","errorType":"exception","errorClass":"java.net.SocketTimeoutException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/servermanager/LocalServerManager.java","lineNumber":323,"sourceCode":"                    }\n                    if (response.startsWith(\"Error!\")) {\n                        readFailure.set(new IOException(response));\n                        break;\n                    }\n                }\n            } catch (Throwable e) {\n                readFailure.set(e);\n            } finally {\n                commandWatcher.countDown();\n            }\n        }, \"am-adb-command-output\");\n        outputThread.start();\n        try {\n            outputStream.write(\"id\\n\".getBytes(StandardCharsets.UTF_8));\n            outputStream.write((command + \"\\n\").getBytes(StandardCharsets.UTF_8));\n            outputStream.flush();\n            if (!commandWatcher.await(timeout, timeoutUnit)) {\n                throw new SocketTimeoutException(\"Timed out waiting for ADB command: \" + command);\n            }\n            if (!commandSucceeded.get()) {\n                Throwable failure = readFailure.get();\n                throw new IOException(\"ADB command did not produce \" + successPrefix, failure);\n            }\n        } finally {\n            outputThread.interrupt();\n        }\n    }\n\n    @WorkerThread\n    private void useRootStartServer() throws Exception {\n        if (!Ops.hasRoot()) {\n            throw new Exception(\"Root access denied\");\n        }\n        String command = ServerConfig.getServerRunnerCommand();\n        // + \"\\n\" + \"supolicy --live 'allow qti_init_shell zygote_exec file execute'\";\n        Log.d(TAG, \"useRootStartServer: %s\", command);","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/servermanager/LocalServerManager.java#L305-L341","documentation":"LocalServerManager.executeAdbCommand sends a command over the ADB shell stream and uses a CountDownLatch (commandWatcher) that is counted down when success/failure markers are seen on the output. If neither marker arrives within the timeout, it throws SocketTimeoutException, meaning the remote shell never produced the expected output.","triggerScenarios":"Calling executeAdbCommand when the ADB shell is hung or the daemon dies mid-command, the command blocks indefinitely (e.g. waiting on input), or output parsing never sees the success prefix within the configured timeout.","commonSituations":"Device under heavy load making the shell slow; ADB stream silently dropped (wireless debugging hiccup); command producing unexpected output so the success/failure prefix is never matched; timeout set too low.","solutions":["Increase the timeout (timeout/timeoutUnit arguments) to accommodate slow devices","Verify the command is valid and produces output matching successPrefix","Re-check ADB connectivity (openAdbShell again) since the stream may have died","Retry the command; transient wireless-debugging drops often resolve on a second attempt"],"exampleFix":"// before\nserverManager.executeAdbCommand(cmd, 10, TimeUnit.SECONDS);\n// after\ntry {\n    serverManager.executeAdbCommand(cmd, 30, TimeUnit.SECONDS);\n} catch (SocketTimeoutException e) {\n    // reconnect ADB shell and retry once\n}","handlingStrategy":"retry","validationCode":"// ensure shell stream is alive and command is well-formed first\nif (!shellStream.isClosed()) {\n    sendKeepAlive(); // e.g. write \"id\\n\" and check the success prefix before the real command\n}","typeGuard":null,"tryCatchPattern":"try {\n    result = executeAdbCommand(cmd, timeout, unit);\n} catch (SocketTimeoutException e) {\n    // reconnect the ADB shell and retry once with a longer timeout\n}","preventionTips":["Send a probe command (id) and verify response before real commands — the code already does this","Choose timeouts appropriate for slow/loaded devices","Validate that command output will contain the expected successPrefix","Detect dead ADB streams early and reconnect rather than blocking on await()"],"tags":["adb","timeout","network","android"],"backgroundTag":"request-timeout","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}