Skip to content

Commit 61ce724

Browse files
committed
New tool runner, based on the new process runner
AdbRunner implemented with the new tool runner
1 parent 371d3bb commit 61ce724

File tree

11 files changed

+514
-70
lines changed

11 files changed

+514
-70
lines changed

tools/xadebug/Xamarin.Android.Debug/AndroidDevice.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class AndroidDevice
4747
string outputDir;
4848

4949
XamarinLoggingHelper log;
50-
AdbRunner adb;
50+
AdbRunner2 adb;
5151
AndroidNdk ndk;
5252

5353
public int ApiLevel => apiLevel;
@@ -62,9 +62,9 @@ class AndroidDevice
6262
public string LldbBaseDir => appLldbBaseDir ?? String.Empty;
6363
public string AppDataDir => appDataDir ?? String.Empty;
6464
public string? DeviceLddPath => deviceLdd;
65-
public AdbRunner AdbRunner => adb;
65+
public AdbRunner2 AdbRunner => adb;
6666

67-
public AndroidDevice (XamarinLoggingHelper log, AndroidNdk ndk, string outputDir, string adbPath, string packageName, List<string> supportedAbis, string? adbTargetDevice = null)
67+
public AndroidDevice (XamarinLoggingHelper log, IProcessOutputLogger processLogger, AndroidNdk ndk, string outputDir, string adbPath, string packageName, List<string> supportedAbis, string? adbTargetDevice = null)
6868
{
6969
this.adbPath = adbPath;
7070
this.log = log;
@@ -73,7 +73,7 @@ public AndroidDevice (XamarinLoggingHelper log, AndroidNdk ndk, string outputDir
7373
this.ndk = ndk;
7474
this.outputDir = outputDir;
7575

76-
adb = new AdbRunner (log, adbPath, adbTargetDevice);
76+
adb = new AdbRunner2 (log, processLogger, adbPath, adbTargetDevice);
7777
}
7878

7979
// TODO: implement manual error checking on API 21, since `adb` won't ever return any error code other than 0 - we need to look at the output of any command to determine

tools/xadebug/Xamarin.Android.Debug/DebugSession.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public bool Prepare ()
5050

5151
ndk = new AndroidNdk (log, parsedOptions.NdkDirPath!, supportedAbis);
5252
device = new AndroidDevice (
53-
log,
53+
log, // general logger
54+
log, // process output logger
5455
ndk,
5556
workDirectory,
5657
parsedOptions.AdbPath,

tools/xadebug/Xamarin.Android.Debug/DeviceLibrariesCopier.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ abstract class DeviceLibraryCopier
1010
protected XamarinLoggingHelper Log { get; }
1111
protected bool AppIs64Bit { get; }
1212
protected string LocalDestinationDir { get; }
13-
protected AdbRunner Adb { get; }
13+
protected AdbRunner2 Adb { get; }
1414
protected AndroidDevice Device { get; }
1515

16-
protected DeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
16+
protected DeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner2 adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
1717
{
1818
Log = log;
1919
Adb = adb;

tools/xadebug/Xamarin.Android.Debug/LddDeviceLibrariesCopier.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22
using System.Collections.Generic;
33

44
using Xamarin.Android.Utilities;
5-
using Xamarin.Android.Tasks;
65

76
namespace Xamarin.Android.Debug;
87

98
class LddDeviceLibraryCopier : DeviceLibraryCopier
109
{
11-
public LddDeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
10+
public LddDeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner2 adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
1211
: base (log, adb, appIs64Bit, localDestinationDir, device)
1312
{}
1413

tools/xadebug/Xamarin.Android.Debug/NoLddDeviceLibrariesCopier.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class NoLddDeviceLibraryCopier : DeviceLibraryCopier
3434
"/system/vendor/@LIB@/mediadrm",
3535
};
3636

37-
public NoLddDeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
37+
public NoLddDeviceLibraryCopier (XamarinLoggingHelper log, AdbRunner2 adb, bool appIs64Bit, string localDestinationDir, AndroidDevice device)
3838
: base (log, adb, appIs64Bit, localDestinationDir, device)
3939
{}
4040

@@ -61,7 +61,7 @@ public override bool Copy (out string? zygotePath)
6161

6262
void AddSharedLibraries (List<string> sharedLibraries, string deviceDirPath, HashSet<string> permittedPaths)
6363
{
64-
AdbRunner.OutputLineFilter filterOutErrors = (bool isStdError, string line) => {
64+
AdbRunner2.OutputLineFilter filterOutErrors = (bool isStdError, string line) => {
6565
if (!isStdError) {
6666
return false; // don't suppress any lines on stdout
6767
}
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
5+
namespace Xamarin.Android.Utilities;
6+
7+
class AdbRunner2 : ToolRunner2
8+
{
9+
public delegate bool OutputLineFilter (bool isStdErr, string line);
10+
11+
sealed class CaptureOutputState
12+
{
13+
public OutputLineFilter? LineFilter;
14+
public CaptureProcessOutputLogger? Logger;
15+
}
16+
17+
sealed class CaptureProcessOutputLogger : IProcessOutputLogger
18+
{
19+
IProcessOutputLogger? wrappedLogger;
20+
OutputLineFilter? lineFilter;
21+
List<string> lines;
22+
string? stderrPrefix;
23+
string? stdoutPrefix;
24+
25+
public List<string> Lines => lines;
26+
27+
public IProcessOutputLogger? WrappedLogger => wrappedLogger;
28+
29+
public string? StdoutPrefix {
30+
get => stdoutPrefix ?? wrappedLogger?.StdoutPrefix ?? String.Empty;
31+
set => stdoutPrefix = value;
32+
}
33+
34+
public string? StderrPrefix {
35+
get => stderrPrefix ?? wrappedLogger?.StderrPrefix ?? String.Empty;
36+
set => stderrPrefix = value;
37+
}
38+
39+
public CaptureProcessOutputLogger (IProcessOutputLogger? wrappedLogger, OutputLineFilter? lineFilter = null)
40+
{
41+
this.wrappedLogger = wrappedLogger;
42+
this.lineFilter = lineFilter;
43+
44+
lines = new List<string> ();
45+
}
46+
47+
public void WriteStderr (string text, bool writeLine = true)
48+
{
49+
if (LineFiltered (text, isStdError: true)) {
50+
return;
51+
}
52+
53+
wrappedLogger?.WriteStderr (text, writeLine);
54+
}
55+
56+
public void WriteStdout (string text, bool writeLine = true)
57+
{
58+
if (LineFiltered (text, isStdError: false)) {
59+
return;
60+
}
61+
62+
lines.Add (text);
63+
}
64+
65+
bool LineFiltered (string text, bool isStdError)
66+
{
67+
if (lineFilter == null) {
68+
return false;
69+
}
70+
71+
return lineFilter (isStdError, text);
72+
}
73+
}
74+
75+
string[]? initialParams;
76+
77+
public AdbRunner2 (ILogger logger, IProcessOutputLogger processOutputLogger, string adbPath, string? deviceSerial = null)
78+
: base (adbPath, logger, processOutputLogger)
79+
{
80+
if (!String.IsNullOrEmpty (deviceSerial)) {
81+
initialParams = new string[] { "-s", deviceSerial };
82+
}
83+
}
84+
85+
public async Task<bool> Pull (string remotePath, string localPath)
86+
{
87+
var runner = CreateAdbRunner ();
88+
runner.AddArgument ("pull");
89+
runner.AddArgument (remotePath);
90+
runner.AddArgument (localPath);
91+
92+
return await RunAdbAsync (runner);
93+
}
94+
95+
public async Task<bool> Push (string localPath, string remotePath)
96+
{
97+
var runner = CreateAdbRunner ();
98+
runner.AddArgument ("push");
99+
runner.AddArgument (localPath);
100+
runner.AddArgument (remotePath);
101+
102+
return await RunAdbAsync (runner);
103+
}
104+
105+
public async Task<bool> Install (string apkPath, bool apkIsDebuggable = false, bool replaceExisting = true, bool noStreaming = true)
106+
{
107+
var runner = CreateAdbRunner ();
108+
runner.AddArgument ("install");
109+
110+
if (replaceExisting) {
111+
runner.AddArgument ("-r");
112+
}
113+
114+
if (apkIsDebuggable) {
115+
runner.AddArgument ("-d"); // Allow version code downgrade
116+
}
117+
118+
if (noStreaming) {
119+
runner.AddArgument ("--no-streaming");
120+
}
121+
122+
runner.AddQuotedArgument (apkPath);
123+
124+
return await RunAdbAsync (runner);
125+
}
126+
127+
public async Task<(bool success, string output)> GetAppDataDirectory (string packageName)
128+
{
129+
return await RunAs (packageName, "/system/bin/sh", "-c", "pwd");
130+
}
131+
132+
133+
public async Task<(bool success, string output)> CreateDirectoryAs (string packageName, string directoryPath)
134+
{
135+
return await RunAs (packageName, "mkdir", "-p", directoryPath);
136+
}
137+
138+
public async Task<(bool success, string output)> GetPropertyValue (string propertyName)
139+
{
140+
var runner = CreateAdbRunner ();
141+
return await Shell ("getprop", propertyName);
142+
}
143+
144+
public async Task<(bool success, string output)> RunAs (string packageName, string command, params string[] args)
145+
{
146+
if (String.IsNullOrEmpty (packageName)) {
147+
throw new ArgumentException ("must not be null or empty", nameof (packageName));
148+
}
149+
150+
var shellArgs = new List<string> {
151+
packageName,
152+
command,
153+
};
154+
155+
if (args != null && args.Length > 0) {
156+
shellArgs.AddRange (args);
157+
}
158+
159+
return await Shell ("run-as", (IEnumerable<string>)shellArgs, lineFilter: null);
160+
}
161+
162+
public async Task<(bool success, string output)> Shell (string command, List<string> args, OutputLineFilter? lineFilter = null)
163+
{
164+
return await Shell (command, (IEnumerable<string>)args, lineFilter);
165+
}
166+
167+
public async Task<(bool success, string output)> Shell (string command, params string[] args)
168+
{
169+
return await Shell (command, (IEnumerable<string>)args, lineFilter: null);
170+
}
171+
172+
public async Task<(bool success, string output)> Shell (OutputLineFilter lineFilter, string command, params string[] args)
173+
{
174+
return await Shell (command, (IEnumerable<string>)args, lineFilter);
175+
}
176+
177+
async Task<(bool success, string output)> Shell (string command, IEnumerable<string>? args, OutputLineFilter? lineFilter)
178+
{
179+
if (String.IsNullOrEmpty (command)) {
180+
throw new ArgumentException ("must not be null or empty", nameof (command));
181+
}
182+
183+
var captureState = new CaptureOutputState {
184+
LineFilter = lineFilter,
185+
};
186+
187+
var runner = CreateAdbRunner (captureState);
188+
189+
runner.AddArgument ("shell");
190+
runner.AddArgument (command);
191+
runner.AddArguments (args);
192+
193+
return await CaptureAdbOutput (runner, captureState);
194+
}
195+
196+
async Task<bool> RunAdbAsync (ProcessRunner2 runner)
197+
{
198+
ProcessStatus status = await runner.RunAsync ();
199+
return status.Success;
200+
}
201+
202+
async Task<(bool success, string output)> CaptureAdbOutput (ProcessRunner2 runner, CaptureOutputState captureState)
203+
{
204+
ProcessStatus status = await runner.RunAsync ();
205+
206+
string output = captureState.Logger != null ? String.Join (Environment.NewLine, captureState.Logger.Lines) : String.Empty;
207+
return (status.Success, output);
208+
}
209+
210+
ProcessRunner2 CreateAdbRunner (CaptureOutputState? state = null) => InitProcessRunner (state, initialParams);
211+
212+
protected override ProcessRunner2 CreateProcessRunner (IProcessOutputLogger consoleProcessLogger, object? state, params string?[]? initialParams)
213+
{
214+
IProcessOutputLogger outputLogger;
215+
216+
if (state is CaptureOutputState captureState) {
217+
captureState.Logger = new CaptureProcessOutputLogger (consoleProcessLogger, captureState.LineFilter);
218+
outputLogger = captureState.Logger;
219+
} else {
220+
outputLogger = consoleProcessLogger;
221+
}
222+
223+
outputLogger.StderrPrefix = "adb> ";
224+
ProcessRunner2 ret = base.CreateProcessRunner (outputLogger, initialParams);
225+
226+
// Let's make sure all the messages we get are in English, since we need to parse some of them to detect problems
227+
ret.Environment["LANG"] = "C";
228+
return ret;
229+
}
230+
}

tools/xadebug/Xamarin.Android.Utilities/IProcessOutputLogger.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ namespace Xamarin.Android.Utilities;
22

33
interface IProcessOutputLogger
44
{
5-
void WriteStdout (string text);
6-
void WriteStderr (string text);
5+
IProcessOutputLogger? WrappedLogger { get; }
6+
string? StdoutPrefix { get; set; }
7+
string? StderrPrefix { get; set; }
8+
9+
void WriteStdout (string text, bool writeLine = true);
10+
void WriteStderr (string text, bool writeLine = true);
711
}

0 commit comments

Comments
 (0)