/// <inheritdoc/> protected void Root(string request, DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest(request); var response = socket.ReadAdbResponse(); // ADB will send some additional data byte[] buffer = new byte[1024]; int read = socket.Read(buffer); var responseMessage = Encoding.UTF8.GetString(buffer, 0, read); // See https://android.googlesource.com/platform/system/core/+/master/adb/commandline.cpp#1026 (adb_root) // for more information on how upstream does this. if (!string.Equals(responseMessage, "restarting", StringComparison.OrdinalIgnoreCase)) { throw new AdbException(responseMessage); } else { // Give adbd some time to kill itself and come back up. // We can't use wait-for-device because devices (e.g. adb over network) might not come back. Task.Delay(3000).GetAwaiter().GetResult(); } } }
/// <inheritdoc/> public void Install(DeviceData device, Stream apk, params string[] arguments) { this.EnsureDevice(device); if (apk == null) { throw new ArgumentNullException(nameof(apk)); } if (!apk.CanRead || !apk.CanSeek) { throw new ArgumentOutOfRangeException(nameof(apk), "The apk stream must be a readable and seekable stream"); } StringBuilder requestBuilder = new StringBuilder(); requestBuilder.Append("exec:cmd package 'install' "); if (arguments != null) { foreach (var argument in arguments) { requestBuilder.Append(" "); requestBuilder.Append(argument); } } // add size parameter [required for streaming installs] // do last to override any user specified value requestBuilder.Append($" -S {apk.Length}"); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest(requestBuilder.ToString()); var response = socket.ReadAdbResponse(); byte[] buffer = new byte[32 * 1024]; int read = 0; while ((read = apk.Read(buffer, 0, buffer.Length)) > 0) { socket.Send(buffer, read); } read = socket.Read(buffer); var value = Encoding.UTF8.GetString(buffer, 0, read); if (!string.Equals(value, "Success\n")) { throw new AdbException(value); } } }
/// <inheritdoc/> public async Task RunLogServiceAsync(DeviceData device, Action <LogEntry> messageSink, CancellationToken cancellationToken, params LogId[] logNames) { if (messageSink == null) { throw new ArgumentException(nameof(messageSink)); } this.EnsureDevice(device); // The 'log' service has been deprecated, see // https://android.googlesource.com/platform/system/core/+/7aa39a7b199bb9803d3fd47246ee9530b4a96177 using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); StringBuilder request = new StringBuilder(); request.Append("shell:logcat -B"); foreach (var logName in logNames) { request.Append($" -b {logName.ToString().ToLowerInvariant()}"); } socket.SendAdbRequest(request.ToString()); var response = socket.ReadAdbResponse(); using (Stream stream = socket.GetShellStream()) { LogReader reader = new LogReader(stream); while (!cancellationToken.IsCancellationRequested) { LogEntry entry = null; try { entry = await reader.ReadEntry(cancellationToken).ConfigureAwait(false); } catch (EndOfStreamException) { // This indicates the end of the stream; the entry will remain null. } if (entry != null) { messageSink(entry); } else { break; } } } } }
/// <inheritdoc/> public async Task ExecuteRemoteCommandAsync(string command, DeviceData device, IShellOutputReceiver receiver, Encoding encoding, CancellationToken cancellationToken) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { cancellationToken.Register(() => socket.Dispose()); socket.SetDevice(device); socket.SendAdbRequest($"shell:{command}"); var response = socket.ReadAdbResponse(); try { using (StreamReader reader = new StreamReader(socket.GetShellStream(), encoding)) { // Previously, we would loop while reader.Peek() >= 0. Turns out that this would // break too soon in certain cases (about every 10 loops, so it appears to be a timing // issue). Checking for reader.ReadLine() to return null appears to be much more robust // -- one of the integration test fetches output 1000 times and found no truncations. while (!cancellationToken.IsCancellationRequested) { var line = await reader.ReadLineAsync().ConfigureAwait(false); if (line == null) { break; } if (receiver != null) { receiver.AddOutput(line); } } } } catch (Exception e) { // If a cancellation was requested, this main loop is interrupted with an exception // because the socket is closed. In that case, we don't need to throw a ShellCommandUnresponsiveException. // In all other cases, something went wrong, and we want to report it to the user. if (!cancellationToken.IsCancellationRequested) { throw new ShellCommandUnresponsiveException(e); } } finally { if (receiver != null) { receiver.Flush(); } } } }
public void RemoveAllReverseForwards(DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest($"reverse:killforward-all"); var response = socket.ReadAdbResponse(); } }
/// <inheritdoc/> public void Reboot(string into, DeviceData device) { this.EnsureDevice(device); var request = $"reboot:{into}"; using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest(request); var response = socket.ReadAdbResponse(); } }
public IEnumerable <ForwardData> ListReverseForward(DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest($"reverse:list-forward"); var response = socket.ReadAdbResponse(); var data = socket.ReadString(); var parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); return(parts.Select(p => ForwardData.FromString(p))); } }
/// <inheritdoc/> public int CreateReverseForward(DeviceData device, string remote, string local, bool allowRebind) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); string rebind = allowRebind ? string.Empty : "norebind:"; socket.SendAdbRequest($"reverse:forward:{rebind}{remote};{local}"); var response = socket.ReadAdbResponse(); response = socket.ReadAdbResponse(); var portString = socket.ReadString(); if (portString != null && int.TryParse(portString, out int port)) { return(port); } return(0); } }