/// <inheritdoc/> protected void Root(string request, DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { this.SetDevice(socket, 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(); } } }
public VirtualDrive(DeviceData device, IAdbSocket client, char letter) { AndroidDevice = device; Label = device.Serial; DriveLetter = letter; Sync = new SyncService(client, device); }
/// <inheritdoc/> public bool CreateReverse(DeviceData device, string local, string remote, bool allowRebind) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { string rebind = allowRebind ? string.Empty : "norebind:"; socket.SendAdbRequest("host:transport:" + device.Serial); var response = socket.ReadAdbResponse(); if (!response.Okay) { return(false); } socket.SendAdbRequest($"reverse:forward:{rebind}{local};{remote}"); response = socket.ReadAdbResponse(); if (!response.Okay) { return(false); } return(true); } }
/// <inheritdoc/> public bool RemoveAllReverse(DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SendAdbRequest("host:transport:" + device.Serial); var response = socket.ReadAdbResponse(); if (!response.Okay) { return(false); } socket.SendAdbRequest($"reverse:killforward-all"); response = socket.ReadAdbResponse(); if (!response.Okay) { return(false); } } return(true); }
/// <inheritdoc/> public void SetDevice(IAdbSocket socket, DeviceData device) { // if the device is not null, then we first tell adb we're looking to talk // to a specific device if (device != null) { socket.SendAdbRequest($"host:transport:{device.Serial}"); try { var response = socket.ReadAdbResponse(); } catch (AdbException e) { if (string.Equals("device not found", e.AdbError, StringComparison.OrdinalIgnoreCase)) { throw new DeviceNotFoundException(device.Serial); } else { throw; } } } }
/// <include file='IAdbClient.xml' path='/IAdbClient/GetFrameBuffer/*'/> public async Task <Image> GetFrameBuffer(DeviceData device, CancellationToken cancellationToken) { using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { // Select the target device this.SetDevice(socket, device); // Send the framebuffer command socket.SendAdbRequest("framebuffer:"); socket.ReadAdbResponse(); // The result first is a FramebufferHeader object, var size = Marshal.SizeOf(typeof(FramebufferHeader)); var headerData = new byte[size]; await socket.ReadAsync(headerData, cancellationToken).ConfigureAwait(false); var header = FramebufferHeader.Read(headerData); // followed by the actual framebuffer content var imageData = new byte[header.Size]; socket.Read(imageData); // Convert the framebuffer to an image, and return that. return(header.ToImage(imageData)); } }
/// <summary> /// Initializes a new instance of the <see cref="SyncService"/> class. /// </summary> /// <param name="socket"> /// A <see cref="IAdbSocket"/> that enables to connection with the /// adb server. /// </param> /// <param name="device"> /// The device on which to interact with the files. /// </param> public SyncService(IAdbSocket socket, DeviceData device) { this.Socket = socket; this.Device = device; this.Open(); }
/// <inheritdoc/> public IEnumerable <ForwardData> ListReverse(DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SendAdbRequest("host:transport:" + device.Serial); var response = socket.ReadAdbResponse(); if (!response.Okay) { return(null); } socket.SendAdbRequest($"reverse:list-forward"); response = socket.ReadAdbResponse(); if (!response.Okay) { return(null); } var data = socket.ReadString(); var parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); return(parts.Select(p => ForwardData.FromString(p))); } }
/// <include file='IAdbClient.xml' path='/IAdbClient/RemoveForward/*'/> public void RemoveForward(DeviceData device, int localPort) { using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { socket.SendAdbRequest($"host-serial:{device.Serial}:killforward:tcp:{localPort}"); var response = socket.ReadAdbResponse(); } }
/// <include file='IAdbClient.xml' path='/IAdbClient/RemoveAllForwards/*'/> public void RemoveAllForwards(DeviceData device) { using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { socket.SendAdbRequest($"host-serial:{device.Serial}:killforward-all"); var response = socket.ReadAdbResponse(); } }
/// <inheritdoc/> public void KillAdb() { using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SendAdbRequest("host:kill"); // The host will immediately close the connection after the kill // command has been sent; no need to read the response. } }
/// <include file='IAdbClient.xml' path='/IAdbClient/CreateForward/*'/> public void CreateForward(DeviceData device, string local, string remote, bool allowRebind) { using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { string rebind = allowRebind ? string.Empty : "norebind:"; socket.SendAdbRequest($"host-serial:{device.Serial}:forward:{rebind}{local};{remote}"); var response = socket.ReadAdbResponse(); } }
/// <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)) { this.SetDevice(socket, 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 ExecuteRemoteCommandAsync(string command, DeviceData device, IShellOutputReceiver receiver, CancellationToken cancellationToken, int maxTimeToOutputResponse) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { cancellationToken.Register(() => socket.Dispose()); this.SetDevice(socket, 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(); } } } }
/// <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)) { this.SetDevice(socket, 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; } } } } }
/// <summary> /// Initializes a new instance of the <see cref="DeviceMonitor"/> class. /// </summary> /// <param name="socket"> /// The <see cref="IAdbSocket"/> that manages the connection with the adb server. /// </param> public DeviceMonitor(IAdbSocket socket) { if (socket == null) { throw new ArgumentNullException(nameof(socket)); } this.Socket = socket; this.devices = new List <DeviceData>(); this.Devices = this.devices.AsReadOnly(); }
/// <summary> /// Initializes a new instance of the <see cref="DeviceMonitor"/> class. /// </summary> /// <param name="socket"> /// The <see cref="IAdbSocket"/> that manages the connection with the adb server. /// </param> public DeviceMonitor(IAdbSocket socket) { if (socket == null) { throw new ArgumentNullException(nameof(socket)); } this.Socket = socket; this.devices = new List<DeviceData>(); this.Devices = this.devices.AsReadOnly(); }
/// <include file='IAdbClient.xml' path='/IAdbClient/Reboot/*'/> public void Reboot(string into, DeviceData device) { var request = $"reboot:{into}"; using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { this.SetDevice(socket, device); socket.SendAdbRequest(request); var response = socket.ReadAdbResponse(); } }
public void RemoveReverseForward(DeviceData device, string remote) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SetDevice(device); socket.SendAdbRequest($"reverse:killforward:{remote}"); var response = socket.ReadAdbResponse(); } }
/// <summary> /// Initializes a new instance of the <see cref="DeviceMonitor"/> class. /// </summary> /// <param name="socket"> /// The <see cref="IAdbSocket"/> that manages the connection with the adb server. /// </param> /// <param name="logger"> /// The logger to use when logging. /// </param> public DeviceMonitor(IAdbSocket socket, ILogger <DeviceMonitor> logger = null) { if (socket == null) { throw new ArgumentNullException(nameof(socket)); } this.Socket = socket; this.devices = new List <DeviceData>(); this.Devices = this.devices.AsReadOnly(); this.logger = logger ?? NullLogger <DeviceMonitor> .Instance; }
public void Close() { if (Block != null) { Block.Complete(); } _outputBlock.Complete(); _inputBlock.Complete(); LocalId = 0; RemoteId = 0; _sock = null; }
public void RemoveAllReverseForwards(DeviceData device) { this.EnsureDevice(device); using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { this.SetDevice(socket, device); socket.SendAdbRequest($"reverse:killforward-all"); var response = socket.ReadAdbResponse(); } }
public void Disconnect(DnsEndPoint endpoint) { if (endpoint == null) { throw new ArgumentNullException(nameof(endpoint)); } using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SendAdbRequest($"host:disconnect:{endpoint.Host}:{endpoint.Port}"); var response = socket.ReadAdbResponse(); } }
/// <inheritdoc/> public List <DeviceData> GetDevices() { using (IAdbSocket socket = this.adbSocketFactory(this.EndPoint)) { socket.SendAdbRequest("host:devices-l"); socket.ReadAdbResponse(); var reply = socket.ReadString(); string[] data = reply.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); return(data.Select(d => DeviceData.CreateFromAdbData(d)).ToList()); } }
/// <include file='IAdbClient.xml' path='/IAdbClient/ListForward/*'/> public IEnumerable <ForwardData> ListForward(DeviceData device) { using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { socket.SendAdbRequest($"host-serial:{device.Serial}: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))); } }
public async Task <IPropagatorBlock <byte[], byte[]> > ExecuteRemoteCommandAsyncBlock(string cmd, DeviceData d, CancellationToken ct, int maxTimeToOutputResponse, Encoding encoding) { this.EnsureDevice(d); using (IAdbSocket sock = this.GetSocket()) { this.SetDevice(sock, d); uint streamId = 1; sock.SendAdbRequest($"shell:{cmd}"); var ss = sock.GetShellStream(); var stream = new AdbLocalStream(sock, streamId, encoding, ct); //OpenStreams.Add(streamId, stream); return(stream.Block); } }
/// <inheritdoc/> public IEnumerable <LogEntry> RunLogService(DeviceData device, params LogId[] logNames) { this.EnsureDevice(device); // The 'log' service has been deprecated, see // https://android.googlesource.com/platform/system/core/+/7aa39a7b199bb9803d3fd47246ee9530b4a96177 using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { this.SetDevice(socket, device); StringBuilder request = new StringBuilder(); request.Append("shell:logcat -B"); foreach (var logName in logNames) { request.Append($" -b {logName.ToString().ToLower()}"); } socket.SendAdbRequest(request.ToString()); var response = socket.ReadAdbResponse(); using (Stream stream = socket.GetShellStream()) using (LogReader reader = new LogReader(stream)) { while (true) { LogEntry entry = null; try { entry = reader.ReadEntry(); } catch (EndOfStreamException) { // This indicates the end of the stream; the entry will remain null. } if (entry != null) { yield return(entry); } else { break; } } } } }
/// <inheritdoc/> public string Connect(DnsEndPoint endpoint) { if (endpoint == null) { throw new ArgumentNullException(nameof(endpoint)); } using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { socket.SendAdbRequest($"host:connect:{endpoint.Host}:{endpoint.Port}"); var response = socket.ReadAdbResponse(); return(socket.ReadString()); } }
public override void ReadFrom(IAdbSocket socket) { this.Command = socket.ReadSyncResponse(); var reply = new byte[4]; socket.Read(reply); if (!BitConverter.IsLittleEndian) { Array.Reverse(reply); } // The first 4 bytes contain the length of the data packet this.Size = BitConverter.ToInt32(reply, 0); }
public AdbStream(IAdbSocket sock, uint localId) { _sock = sock; this.LocalId = localId; _outputBlock = new BufferBlock <byte[]>(); _inputBlock = new ActionBlock <byte[]>(bytes => { var buff = Command.CreateWriteCommand(LocalId, RemoteId, bytes); OnWriting?.Invoke(this, EventArgs.Empty); if (RemoteId == 0) { throw new Exception("Remote stream not established yet!"); } _sock.Send(buff, buff.Length); }); Block = DataflowBlock.Encapsulate(_inputBlock, _outputBlock); }
public override void ReadFrom(IAdbSocket socket) { this.Command = socket.ReadSyncResponse(); byte[] statResult = new byte[12]; socket.Read(statResult); if (!BitConverter.IsLittleEndian) { Array.Reverse(statResult, 0, 4); Array.Reverse(statResult, 4, 4); Array.Reverse(statResult, 8, 4); } this.FileMode = (UnixFileMode)BitConverter.ToInt32(statResult, 0); this.Size = BitConverter.ToInt32(statResult, 4); this.Time = DateTimeHelper.Epoch.AddSeconds(BitConverter.ToInt32(statResult, 8)).ToLocalTime(); }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { if (this.Socket != null) { this.Socket.Dispose(); this.Socket = null; } }
public void SetDevice(IAdbSocket socket, DeviceData device) { throw new NotImplementedException(); }
/// <summary> /// Stops the monitoring /// </summary> public void Dispose() { // Close the connection to adb. // This will also cause the socket to disconnect, and the // monitor thread to cancel out (because an ObjectDisposedException is thrown // on the GetString method and subsequently Socket.Connected = false and Socket = null). if (this.Socket != null) { this.Socket.Dispose(); this.Socket = null; } if (this.monitorThread != null) { this.IsRunning = false; // Stop the thread. The tread will keep waiting for updated information from adb // eternally, so we need to forcefully abort it here. this.monitorThread.Abort(); this.monitorThread = null; } }