/// <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)); } }
protected SocketBasedTests(bool integrationTest, bool doDispose) { this.EndPoint = AdbClient.Instance.EndPoint; #if DEBUG // Use the tracing adb socket factory to run the tests on an actual device. // use the dummy socket factory to run unit tests. if (integrationTest) { var tracingSocket = new TracingAdbSocket(this.EndPoint) { DoDispose = doDispose }; Factories.AdbSocketFactory = (endPoint) => tracingSocket; } else { var socket = new DummyAdbSocket(); Factories.AdbSocketFactory = (endPoint) => socket; } this.IntegrationTest = integrationTest; #else // In release mode (e.g. on the build server), // never run integration tests. var socket = new DummyAdbSocket(); Factories.AdbSocketFactory = (endPoint) => socket; this.IntegrationTest = false; #endif this.Socket = (IDummyAdbSocket)Factories.AdbSocketFactory(this.EndPoint); this.TestClient = new AdbClient(); AdbClient.Instance = this.TestClient; }
/// <summary> /// Asynchronously refreshes the framebuffer: fetches the latest framebuffer data from the device. Access the <see cref="Header"/> /// and <see cref="Data"/> properties to get the updated framebuffer data. /// </summary> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous task. /// </param> /// <returns> /// A <see cref="Task"/> which represents the asynchronous operation. /// </returns> public async Task RefreshAsync(CancellationToken cancellationToken) { var socket = Factories.AdbSocketFactory(this.client.EndPoint); // Select the target device this.client.SetDevice(socket, this.Device); // Send the framebuffer command socket.SendAdbRequest("framebuffer:"); socket.ReadAdbResponse(); // The result first is a FramebufferHeader object, await socket.ReadAsync(this.headerData, cancellationToken).ConfigureAwait(false); if (!this.headerInitialized) { this.Header = FramebufferHeader.Read(this.headerData); this.headerInitialized = true; } if (this.Data == null || this.Data.Length < this.Header.Size) { this.Data = new byte[this.Header.Size]; } // followed by the actual framebuffer content await socket.ReadAsync(this.Data, (int)this.Header.Size, cancellationToken).ConfigureAwait(false); }
/// <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(); } }
/// <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/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 KillAdb() { using (IAdbSocket socket = Factories.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. } }
/// <inheritdoc/> public void ExecuteRemoteCommand(string command, DeviceData device, IShellOutputReceiver receiver, CancellationToken cancellationToken, int maxTimeToOutputResponse) { this.EnsureDevice(device); using (IAdbSocket socket = Factories.AdbSocketFactory(this.EndPoint)) { cancellationToken.Register(() => socket.Close()); 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 = reader.ReadLine(); 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 = 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().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; } } } } }
/// <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(); } }
/// <inheritdoc/> public int GetAdbVersion() { using (var socket = Factories.AdbSocketFactory(this.EndPoint)) { socket.SendAdbRequest("host:version"); var response = socket.ReadAdbResponse(); var version = socket.ReadString(); return(int.Parse(version, NumberStyles.HexNumber)); } }
/// <inheritdoc/> public void 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(); } }
/// <inheritdoc/> public List <DeviceData> GetDevices() { using (IAdbSocket socket = Factories.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))); } }
/// <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; } } } } }
/// <summary> /// Asynchronously refreshes the framebuffer: fetches the latest framebuffer data from the device. Access the <see cref="Header"/> /// and <see cref="Data"/> properties to get the updated framebuffer data. /// </summary> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous task. /// </param> /// <returns> /// A <see cref="Task"/> which represents the asynchronous operation. /// </returns> public async Task RefreshAsync(CancellationToken cancellationToken) { this.EnsureNotDisposed(); using (var socket = Factories.AdbSocketFactory(this.client.EndPoint)) { // Select the target device this.client.SetDevice(socket, this.Device); // Send the framebuffer command socket.SendAdbRequest("framebuffer:"); socket.ReadAdbResponse(); // The result first is a FramebufferHeader object, await socket.ReadAsync(this.headerData, cancellationToken).ConfigureAwait(false); if (!this.headerInitialized) { this.Header = FramebufferHeader.Read(this.headerData); this.headerInitialized = true; } if (this.Data == null || this.Data.Length < this.Header.Size) { #if !NETFX // Optimization on .NET Core: Use the BufferPool to rent buffers if (this.Data != null) { ArrayPool <byte> .Shared.Return(this.Data, clearArray : false); } this.Data = ArrayPool <byte> .Shared.Rent((int)this.Header.Size); #else this.Data = new byte[(int)this.Header.Size]; #endif } // followed by the actual framebuffer content await socket.ReadAsync(this.Data, (int)this.Header.Size, cancellationToken).ConfigureAwait(false); } }
/// <summary> /// Initializes a new instance of the <see cref="SyncService"/> class. /// </summary> /// <param name="client"> /// A connection to an adb server. /// </param> /// <param name="device"> /// The device on which to interact with the files. /// </param> public SyncService(IAdbClient client, DeviceData device) : this(Factories.AdbSocketFactory(client.EndPoint), device) { }
/// <summary> /// Initializes a new instance of the <see cref="SyncService"/> class. /// </summary> /// <param name="device"> /// The device on which to interact with the files. /// </param> public SyncService(DeviceData device) : this(Factories.AdbSocketFactory(AdbServer.Instance.EndPoint), device) { }