-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for shell v2 commands #121
base: master
Are you sure you want to change the base?
Conversation
…d stderr as well as exit code
Thanks for this contribution. The code quality is very high. 🙇♂️ Some thoughts.
|
Also what does the V2 refer to here? Can it be dropped? |
Probably, but (1) it makes the code more complicated, as PipedOutputStream could no longer be used -- I'd have to write a custom OutputStream that blocks if we get the wrong output from the multiplexed stream and waits for another thread to read it -- and (2) I think it's a little more prone to user error -- users would always have to use a thread to read output streams, or else the code would deadlock.
Good point, let me change it.
Hmm, not sure where I came up with the "V2" nomenclature. ADB source seems to call it "ShellProtocol". I can reword things. |
Oh, "v2" comes from the actual adb service command: |
…f TransportCallable
Latest commit looks good. Still a bit worried about the threads. Perhaps it's the best solution, but could you explain a bit more. For example we already have a custom Also a test seems to fail somehow.. 🤔 Otherwise looks great. Love the idea of reusing the standard library classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ 🙇
Sorry for late feedback, btw. Was on vacation. :) |
To explain the thread problem in detail, the root of the issue is that the user can call any of 3 methods -- With the thread solution, our thread reads a chunk from the transport stream then (with the help of PipedInput/OutputStream) simply blocks until the user calls the right method - Without the thread, each of All of that is complicated, but doable. The worst part is the Process interface. Without a thread, it becomes impossible to try to run a shell command with a timeout. The normal pattern is using |
Sweet. Last call - Are you sure about this threading thing? I would like if possible to leave out all the executor bits, and let callers do any threading as needed. It should be doable without blocking, even if stdout and stderr can be interleaved in the protocol. Anyway, this is a great contribution, and will merge soon. Just giving you some time to ponder first. |
To explain a bit more what I mean. Instead of reading from the stream and piping to stdout/stderr, we only read from the stream when someone else reads from e.g. the remote process stdin. If we get interleaved stderr packages, we just buffer then until someone reads them. This way the caller can use threads if they want, or just spawn a process and read stdin. 🤷♂ I don't know exactly what this would entail in terms of implementation, certainly a bit more hairy than what is in this PR, but the upside is a better library (imho) |
The main problem with buffering is that that buffer needs to be unbounded to prevent blocking of the remote process which can cause issues if the output is not bounded. Java doesn't have a nice way of select() on streams. You could avoid the use of a thread by breaking the Process abstraction and just provide an interface the streams the {STDOUT,STDERR,Exit} messages. |
Please rebase your branch on top of latest master to trigger a build 🙏 |
Supports separate stdout + stderr as well as exit code.
Using adb source for implementation details (see https://android.googlesource.com/platform/system/core/+/master/adb/shell_protocol.h and related files).
Added tests and confirmed working with emulator.
I'm using Java's Process class and emulating parts of ProcessBuilder. Unfortunately, in order to handle both stdout and stderr, you need concurrency. To do this, I'm using an ExecutorService to spin up a thread which handles the stream demuxing.