Tracking the items that were deliberately deferred from #351 ([AdbRunner] Add ADB forward port management) so they don't get lost.
Background
PR #351 added ForwardPortAsync / RemoveForwardPortAsync / RemoveAllForwardPortsAsync / ListForwardPortsAsync to AdbRunner, mirroring the reverse-port API added in #305. During review, jonathanpeppers raised the question of whether these should use the in-process AdbClient from #327 instead of shelling out to adb. The decision was to keep shelling out for #351 (to stay symmetric with the merged reverse implementation, and to avoid coupling #351 to an unmerged dependency), and capture the broader migration here.
Items
1. Stdout parity for reverse-port methods
ReversePortAsync, RemoveReversePortAsync, and RemoveAllReversePortsAsync (src/Xamarin.Android.Tools.AndroidSdk/Runners/AdbRunner.cs, lines ~267, 289, 304) still pass null for stdout to ProcessUtils.StartProcess and only stderr to ProcessUtils.ThrowIfFailed. After #351, the parallel forward methods capture stdout and pass it to ThrowIfFailed as well, which matches the repo convention ("Include stdout in error diagnostics") and yields richer failure messages because adb sometimes writes errors to stdout. Bring the three reverse methods in line.
2. Migrate AdbRunner to use AdbClient once #327 merges
After #327 (in-process AdbClient for the ADB daemon socket protocol) lands, do a single consistent pass that switches the existing process-based call sites in AdbRunner to use AdbClient:
ListDevicesAsync → host:devices-l (already used by AdbDeviceTracker)
GetShellPropertyAsync / GetEmulatorAvdNameAsync → host:transport:<serial> + shell:<cmd>
- Forward operations →
host-serial:<serial>:forward:… / killforward / killforward-all / host:list-forward
- Reverse operations →
host:transport:<serial> + reverse:forward:… / killforward / killforward-all / list-forward
Open question to resolve as part of the migration: how to preserve the implicit adb start-server behaviour that shelling out gives us today. A bare connect("127.0.0.1", 5037) against a cold daemon will throw SocketException. Options include shelling out to adb start-server once on AdbClient failure, or documenting that callers must ensure the daemon is running.
3. Cross-platform failure-path tests
The current AdbRunner failure-path tests (e.g. GetEmulatorAvdNameAsync_*) rely on a fake adb bash script and are skipped on Windows (4 skips). The migration in item 2 enables driving these tests with an in-memory loopback TcpListener instead, which would run on all platforms. Add tests covering at minimum:
cc @jonathanpeppers @rmarinho
Tracking the items that were deliberately deferred from #351 (
[AdbRunner] Add ADB forward port management) so they don't get lost.Background
PR #351 added
ForwardPortAsync/RemoveForwardPortAsync/RemoveAllForwardPortsAsync/ListForwardPortsAsynctoAdbRunner, mirroring the reverse-port API added in #305. During review, jonathanpeppers raised the question of whether these should use the in-processAdbClientfrom #327 instead of shelling out toadb. The decision was to keep shelling out for #351 (to stay symmetric with the merged reverse implementation, and to avoid coupling #351 to an unmerged dependency), and capture the broader migration here.Items
1. Stdout parity for reverse-port methods
ReversePortAsync,RemoveReversePortAsync, andRemoveAllReversePortsAsync(src/Xamarin.Android.Tools.AndroidSdk/Runners/AdbRunner.cs, lines ~267, 289, 304) still passnullfor stdout toProcessUtils.StartProcessand onlystderrtoProcessUtils.ThrowIfFailed. After #351, the parallel forward methods capture stdout and pass it toThrowIfFailedas well, which matches the repo convention ("Include stdout in error diagnostics") and yields richer failure messages becauseadbsometimes writes errors to stdout. Bring the three reverse methods in line.2. Migrate
AdbRunnerto useAdbClientonce #327 mergesAfter #327 (in-process
AdbClientfor the ADB daemon socket protocol) lands, do a single consistent pass that switches the existing process-based call sites inAdbRunnerto useAdbClient:ListDevicesAsync→host:devices-l(already used byAdbDeviceTracker)GetShellPropertyAsync/GetEmulatorAvdNameAsync→host:transport:<serial>+shell:<cmd>host-serial:<serial>:forward:…/killforward/killforward-all/host:list-forwardhost:transport:<serial>+reverse:forward:…/killforward/killforward-all/list-forwardOpen question to resolve as part of the migration: how to preserve the implicit
adb start-serverbehaviour that shelling out gives us today. A bareconnect("127.0.0.1", 5037)against a cold daemon will throwSocketException. Options include shelling out toadb start-serveronce onAdbClientfailure, or documenting that callers must ensure the daemon is running.3. Cross-platform failure-path tests
The current
AdbRunnerfailure-path tests (e.g.GetEmulatorAvdNameAsync_*) rely on a fakeadbbash script and are skipped on Windows (4 skips). The migration in item 2 enables driving these tests with an in-memory loopbackTcpListenerinstead, which would run on all platforms. Add tests covering at minimum:ForwardPortAsyncfailure surfaces stdout in the thrownInvalidOperationException.Message(lock-in for the change made in [AdbRunner] Add ADB forward port management (follow-up to #305) #351).cc @jonathanpeppers @rmarinho