From d48fc791a657132c3ce5f6e62aba6e537e619482 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Fri, 22 Sep 2023 17:02:49 +0800 Subject: [PATCH 1/9] Update AdvancedSharpAdbClient.Tests C# version --- .github/workflows/build-and-test.yml | 5 +- .../AdbClientTests.Async.cs | 438 ++++++---------- .../AdbClientTests.cs | 478 ++++++------------ .../AdbCommandLineClientTests.Async.cs | 2 - .../AdbCommandLineClientTests.cs | 2 - .../AdbSocketTests.Async.cs | 10 +- .../AdbSocketTests.cs | 8 +- .../DeviceExtensionsTests.Async.cs | 2 + .../DeviceCommands/DeviceExtensionsTests.cs | 2 + .../PackageManagerTests.Async.cs | 4 + .../DeviceCommands/PackageManagerTests.cs | 6 +- .../Dummys/DeviceMonitorSink.cs | 8 +- .../Dummys/DummyTcpSocket.cs | 1 + .../Dummys/TracingAdbSocket.cs | 6 +- .../Extensions/FactoriesLocker.cs | 40 ++ .../Extensions/UtilitiesTests.cs | 2 +- .../Logs/ShellStreamTests.cs | 1 - .../Models/FramebufferTests.cs | 16 +- .../SocketBasedTests.cs | 8 +- .../SyncServiceTests.Async.cs | 30 +- .../SyncServiceTests.cs | 40 +- 21 files changed, 440 insertions(+), 669 deletions(-) create mode 100644 AdvancedSharpAdbClient.Tests/Extensions/FactoriesLocker.cs diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c130b1c3..bfd7d215 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -3,7 +3,7 @@ name: build and test on: [push, pull_request] env: - DOTNET_VERSION: '6.0.x' # The .NET SDK version to use + DOTNET_VERSION: '8.0.x' # The .NET SDK version to use jobs: build-and-test: @@ -16,10 +16,11 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Setup .NET Core + - name: Setup .NET Core App uses: actions/setup-dotnet@v3 with: dotnet-version: ${{env.DOTNET_VERSION}} + dotnet-quality: 'preview' - name: Install dependencies run: dotnet restore -p:FullTargets=false diff --git a/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs b/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs index e675c304..6ba0b93e 100644 --- a/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/AdbClientTests.Async.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Drawing.Imaging; using System.Drawing; +using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net; @@ -14,7 +14,6 @@ using System.Threading.Tasks; using System.Xml; using Xunit; -using System.Data.Common; namespace AdvancedSharpAdbClient.Tests { @@ -26,18 +25,10 @@ public partial class AdbClientTests [Fact] public async void GetAdbVersionAsyncTest() { - string[] responseMessages = new string[] - { - "0020" - }; - - string[] requests = new string[] - { - "host:version" - }; + string[] responseMessages = ["0020"]; + string[] requests = ["host:version"]; int version = 0; - await RunTestAsync( OkResponse, responseMessages, @@ -54,10 +45,7 @@ await RunTestAsync( [Fact] public async void KillAdbAsyncTest() { - string[] requests = new string[] - { - "host:kill" - }; + string[] requests = ["host:kill"]; await RunTestAsync( NoResponses, @@ -72,18 +60,10 @@ await RunTestAsync( [Fact] public async void GetDevicesAsyncTest() { - string[] responseMessages = new string[] - { - "169.254.109.177:5555 device product:VS Emulator 5\" KitKat (4.4) XXHDPI Phone model:5__KitKat__4_4__XXHDPI_Phone device:donatello\n" - }; - - string[] requests = new string[] - { - "host:devices-l" - }; + string[] responseMessages = ["169.254.109.177:5555 device product:VS Emulator 5\" KitKat (4.4) XXHDPI Phone model:5__KitKat__4_4__XXHDPI_Phone device:donatello\n"]; + string[] requests = ["host:devices-l"]; IEnumerable devices = null; - await RunTestAsync( OkResponse, responseMessages, @@ -144,15 +124,8 @@ await RunCreateForwardAsyncTest( [Fact] public async void CreateDuplicateForwardAsyncTest() { - AdbResponse[] responses = new AdbResponse[] - { - AdbResponse.FromError("cannot rebind existing socket") - }; - - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:forward:norebind:tcp:1;tcp:2" - }; + AdbResponse[] responses = [AdbResponse.FromError("cannot rebind existing socket")]; + string[] requests = ["host-serial:169.254.109.177:5555:forward:norebind:tcp:1;tcp:2"]; _ = await Assert.ThrowsAsync(() => RunTestAsync( @@ -168,10 +141,7 @@ public async void CreateDuplicateForwardAsyncTest() [Fact] public async void RemoveForwardAsyncTest() { - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:killforward:tcp:1" - }; + string[] requests = ["host-serial:169.254.109.177:5555:killforward:tcp:1"]; await RunTestAsync( OkResponse, @@ -186,17 +156,17 @@ await RunTestAsync( [Fact] public async void RemoveReverseForwardAsyncTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:killforward:localabstract:test" - }; + ]; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; await RunTestAsync( responses, @@ -211,10 +181,7 @@ await RunTestAsync( [Fact] public async void RemoveAllForwardsAsyncTest() { - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:killforward-all" - }; + string[] requests = ["host-serial:169.254.109.177:5555:killforward-all"]; await RunTestAsync( OkResponse, @@ -229,17 +196,17 @@ await RunTestAsync( [Fact] public async void RemoveAllReversesAsyncTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:killforward-all" - }; + ]; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; await RunTestAsync( responses, @@ -254,18 +221,10 @@ await RunTestAsync( [Fact] public async void ListForwardAsyncTest() { - string[] responseMessages = new string[] - { - "169.254.109.177:5555 tcp:1 tcp:2\n169.254.109.177:5555 tcp:3 tcp:4\n169.254.109.177:5555 tcp:5 local:/socket/1\n" - }; - - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:list-forward" - }; + string[] responseMessages = ["169.254.109.177:5555 tcp:1 tcp:2\n169.254.109.177:5555 tcp:3 tcp:4\n169.254.109.177:5555 tcp:5 local:/socket/1\n"]; + string[] requests = ["host-serial:169.254.109.177:5555:list-forward"]; ForwardData[] forwards = null; - await RunTestAsync( OkResponse, responseMessages, @@ -285,24 +244,21 @@ await RunTestAsync( [Fact] public async void ListReverseForwardAsyncTest() { - string[] responseMessages = new string[] - { - "(reverse) localabstract:scrcpy tcp:100\n(reverse) localabstract: scrcpy2 tcp:100\n(reverse) localabstract: scrcpy3 tcp:100\n" - }; - AdbResponse[] responses = new AdbResponse[] - { + string[] responseMessages = ["(reverse) localabstract:scrcpy tcp:100\n(reverse) localabstract: scrcpy2 tcp:100\n(reverse) localabstract: scrcpy3 tcp:100\n"]; + + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:list-forward" - }; + ]; ForwardData[] forwards = null; - await RunTestAsync( responses, responseMessages, @@ -328,19 +284,19 @@ public async void ExecuteRemoteCommandAsyncTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:echo Hello, World" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Hello, World\r\n"); await using MemoryStream shellStream = new(streamData); @@ -369,19 +325,19 @@ public async void ExecuteRemoteCommandAsyncUnresponsiveTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:echo Hello, World" - }; + ]; ConsoleOutputReceiver receiver = new(); @@ -419,9 +375,13 @@ public async void GetFrameBufferAsyncTest() Framebuffer framebuffer = null; - Factories.AdbSocketFactory = (endPoint) => socket; - framebuffer = await TestClient.GetFrameBufferAsync(device); - + using (FactoriesLocker locker = await FactoriesLocker.WaitAsync()) + { + Factories.AdbSocketFactory = (endPoint) => socket; + framebuffer = await TestClient.GetFrameBufferAsync(device); + Factories.Reset(); + } + Assert.NotNull(framebuffer); Assert.Equal(device, framebuffer.Device); Assert.Equal(16, framebuffer.Data.Length); @@ -474,25 +434,25 @@ public async void RunLogServiceAsyncTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:logcat -B -b system" - }; + ]; ConsoleOutputReceiver receiver = new(); await using Stream stream = File.OpenRead("Assets/logcat.bin"); await using ShellStream shellStream = new(stream, false); - Collection logs = new(); + Collection logs = []; Action sink = logs.Add; await RunTestAsync( @@ -511,14 +471,14 @@ await RunTestAsync( [Fact] public async void RebootAsyncTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reboot:" - }; + ]; await RunTestAsync( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, () => TestClient.RebootAsync(Device)); @@ -662,8 +622,8 @@ public async void ConnectAsyncHostEndpointNullTest() => [Fact] public async void DisconnectAsyncTest() { - string[] requests = new string[] { "host:disconnect:localhost:5555" }; - string[] responseMessages = new string[] { "disconnected 127.0.0.1:5555" }; + string[] requests = ["host:disconnect:localhost:5555"]; + string[] responseMessages = ["disconnected 127.0.0.1:5555"]; await RunTestAsync( OkResponse, @@ -684,11 +644,11 @@ public async void RootAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "root:" - }; + ]; byte[] expectedData = new byte[1024]; byte[] expectedString = Encoding.UTF8.GetBytes("adbd cannot run as root in production builds\n"); @@ -696,12 +656,12 @@ public async void RootAsyncTest() _ = await Assert.ThrowsAsync(() => RunTestAsync( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { expectedData }, + [expectedData], Array.Empty(), () => TestClient.RootAsync(device))); } @@ -718,11 +678,11 @@ public async void UnrootAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "unroot:" - }; + ]; byte[] expectedData = new byte[1024]; byte[] expectedString = Encoding.UTF8.GetBytes("adbd not running as root\n"); @@ -730,12 +690,12 @@ public async void UnrootAsyncTest() _ = await Assert.ThrowsAsync(() => RunTestAsync( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { expectedData }, + [expectedData], Array.Empty(), () => TestClient.UnrootAsync(device))); } @@ -752,14 +712,14 @@ public async void InstallAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install' -S 205774" - }; + ]; // The app data is sent in chunks of 32 kb - Collection applicationDataChuncks = new(); + Collection applicationDataChunks = []; await using (Stream stream = File.OpenRead("Assets/testapp.apk")) { @@ -775,7 +735,7 @@ public async void InstallAsyncTest() else { buffer = buffer.Take(read).ToArray(); - applicationDataChuncks.Add(buffer); + applicationDataChunks.Add(buffer); } } } @@ -785,17 +745,13 @@ public async void InstallAsyncTest() await using (Stream stream = File.OpenRead("Assets/testapp.apk")) { await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { response }, - applicationDataChuncks.ToArray(), + [response], + applicationDataChunks.ToArray(), () => TestClient.InstallAsync(device, stream)); } } @@ -812,23 +768,18 @@ public async void InstallCreateAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-create' -p com.google.android.gms" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Success: created install session [936013062]\r\n"); await using MemoryStream shellStream = new(streamData); string session = string.Empty; - await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -849,14 +800,14 @@ public async void InstallWriteAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-write' -S 205774 936013062 base.apk" - }; + ]; // The app data is sent in chunks of 32 kb - Collection applicationDataChuncks = new(); + Collection applicationDataChuncks = []; await using (Stream stream = File.OpenRead("Assets/testapp.apk")) { @@ -882,16 +833,12 @@ public async void InstallWriteAsyncTest() await using (Stream stream = File.OpenRead("Assets/testapp.apk")) { await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { response }, + [response], applicationDataChuncks.ToArray(), () => TestClient.InstallWriteAsync(device, stream, "base", "936013062")); } @@ -909,21 +856,17 @@ public async void InstallCommitAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-commit' 936013062" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Success\r\n"); await using MemoryStream shellStream = new(streamData); await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -942,23 +885,12 @@ public async void GetFeatureSetAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { - "host-serial:009d1cd696d5194a:features" - }; - - string[] responses = new string[] - { - "sendrecv_v2_brotli,remount_shell,sendrecv_v2,abb_exec,fixed_push_mkdir,fixed_push_symlink_timestamp,abb,shell_v2,cmd,ls_v2,apex,stat_v2\r\n" - }; + string[] requests = ["host-serial:009d1cd696d5194a:features"]; + string[] responses = ["sendrecv_v2_brotli,remount_shell,sendrecv_v2,abb_exec,fixed_push_mkdir,fixed_push_symlink_timestamp,abb,shell_v2,cmd,ls_v2,apex,stat_v2\r\n"]; IEnumerable features = null; - await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - }, + [AdbResponse.OK], responses, requests, async () => features = await TestClient.GetFeatureSetAsync(device)); @@ -980,11 +912,11 @@ public async void DumpScreenStringAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt"); @@ -992,13 +924,8 @@ public async void DumpScreenStringAsyncTest() await using MemoryStream shellStream = new(streamData); string xml = string.Empty; - await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1019,11 +946,11 @@ public async void DumpScreenStringAsyncMIUITest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string miuiDump = File.ReadAllText(@"Assets/dumpscreen_miui.txt"); string cleanMIUIDump = File.ReadAllText(@"Assets/dumpscreen_miui_clean.txt"); @@ -1031,13 +958,8 @@ public async void DumpScreenStringAsyncMIUITest() await using MemoryStream miuiStream = new(miuiStreamData); string miuiXml = string.Empty; - await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, miuiStream, @@ -1058,22 +980,18 @@ public async void DumpScreenStringAsyncEmptyTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; byte[] emptyStreamData = Encoding.UTF8.GetBytes(string.Empty); await using MemoryStream emptyStream = new(emptyStreamData); - string emptyXml = string.Empty; + string emptyXml = string.Empty; await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, emptyStream, @@ -1094,11 +1012,11 @@ public async void DumpScreenStringAsyncErrorTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string errorXml = File.ReadAllText(@"Assets/dumpscreen_error.txt"); byte[] errorStreamData = Encoding.UTF8.GetBytes(errorXml); @@ -1106,11 +1024,7 @@ public async void DumpScreenStringAsyncErrorTest() await Assert.ThrowsAsync(() => RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, errorStream, @@ -1129,24 +1043,19 @@ public async void DumpScreenAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); await using MemoryStream shellStream = new(streamData); XmlDocument xml = null; - await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1171,11 +1080,11 @@ public async void ClickAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:input tap 100 100" - }; + ]; byte[] streamData = Encoding.UTF8.GetBytes(@"java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission at android.os.Parcel.createExceptionOrNull(Parcel.java:2373) @@ -1203,11 +1112,7 @@ at android.os.Binder.execTransactInternal(Binder.java:1165) JavaException exception = await Assert.ThrowsAsync(() => RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1250,22 +1155,18 @@ public async void ClickCordsAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:input tap 100 100" - }; - + ]; + byte[] streamData = Encoding.UTF8.GetBytes(@"Error: Injecting to another application requires INJECT_EVENTS permission"); await using MemoryStream shellStream = new(streamData); _ = await Assert.ThrowsAsync(() => RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1284,22 +1185,18 @@ public async void FindElementAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); await using MemoryStream shellStream = new(streamData); await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1325,22 +1222,18 @@ public async void FindElementsAsyncTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); await using MemoryStream shellStream = new(streamData); await RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1358,15 +1251,8 @@ await RunTestAsync( private Task RunConnectAsyncTest(Func test, string connectString) { - string[] requests = new string[] - { - $"host:connect:{connectString}" - }; - - string[] responseMessages = new string[] - { - $"connected to {connectString}" - }; + string[] requests = [$"host:connect:{connectString}"]; + string[] responseMessages = [$"connected to {connectString}"]; return RunTestAsync( OkResponse, @@ -1377,15 +1263,8 @@ private Task RunConnectAsyncTest(Func test, string connectString) private Task RunPairAsyncTest(Func test, string connectString, string code) { - string[] requests = new string[] - { - $"host:pair:{code}:{connectString}" - }; - - string[] responseMessages = new string[] - { - $"Successfully paired to {connectString} [guid=adb-996198a3-xPRwsQ]" - }; + string[] requests = [$"host:pair:{code}:{connectString}"]; + string[] responseMessages = [$"Successfully paired to {connectString} [guid=adb-996198a3-xPRwsQ]"]; return RunTestAsync( OkResponse, @@ -1396,23 +1275,15 @@ private Task RunPairAsyncTest(Func test, string connectString, string code private Task RunCreateReverseAsyncTest(Func test, string reverseString) { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", $"reverse:forward:{reverseString}", - }; + ]; return RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - AdbResponse.OK - }, - new string[] - { - null - }, + [AdbResponse.OK, AdbResponse.OK, AdbResponse.OK], + [null], requests, () => test(Device)); } @@ -1425,15 +1296,8 @@ private Task RunCreateForwardAsyncTest(Func test, string forwa }; return RunTestAsync( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK - }, - new string[] - { - null - }, + [AdbResponse.OK, AdbResponse.OK], + [null], requests, () => test(Device)); } diff --git a/AdvancedSharpAdbClient.Tests/AdbClientTests.cs b/AdvancedSharpAdbClient.Tests/AdbClientTests.cs index a6df31e0..4710da56 100644 --- a/AdvancedSharpAdbClient.Tests/AdbClientTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbClientTests.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Drawing.Imaging; using System.Drawing; +using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Net; @@ -12,7 +12,6 @@ using System.Text; using System.Xml; using Xunit; -using System.Text.RegularExpressions; namespace AdvancedSharpAdbClient.Tests { @@ -85,18 +84,10 @@ public void CreateAdbForwardRequestTest() [Fact] public void GetAdbVersionTest() { - string[] responseMessages = new string[] - { - "0020" - }; - - string[] requests = new string[] - { - "host:version" - }; + string[] responseMessages = ["0020"]; + string[] requests = ["host:version"]; int version = 0; - RunTest( OkResponse, responseMessages, @@ -113,10 +104,7 @@ public void GetAdbVersionTest() [Fact] public void KillAdbTest() { - string[] requests = new string[] - { - "host:kill" - }; + string[] requests = ["host:kill"]; RunTest( NoResponses, @@ -131,18 +119,10 @@ public void KillAdbTest() [Fact] public void GetDevicesTest() { - string[] responseMessages = new string[] - { - "169.254.109.177:5555 device product:VS Emulator 5\" KitKat (4.4) XXHDPI Phone model:5__KitKat__4_4__XXHDPI_Phone device:donatello\n" - }; - - string[] requests = new string[] - { - "host:devices-l" - }; + string[] responseMessages = ["169.254.109.177:5555 device product:VS Emulator 5\" KitKat (4.4) XXHDPI Phone model:5__KitKat__4_4__XXHDPI_Phone device:donatello\n"]; + string[] requests = ["host:devices-l"]; IEnumerable devices = null; - RunTest( OkResponse, responseMessages, @@ -167,10 +147,7 @@ public void GetDevicesTest() [Fact] public void SetDeviceTest() { - string[] requests = new string[] - { - "host:transport:169.254.109.177:5555" - }; + string[] requests = ["host:transport:169.254.109.177:5555"]; RunTest( OkResponse, @@ -185,14 +162,11 @@ public void SetDeviceTest() [Fact] public void SetInvalidDeviceTest() { - string[] requests = new string[] - { - "host:transport:169.254.109.177:5555" - }; + string[] requests = ["host:transport:169.254.109.177:5555"]; _ = Assert.Throws(() => RunTest( - new AdbResponse[] { AdbResponse.FromError("device not found") }, + [AdbResponse.FromError("device not found")], NoResponseMessages, requests, () => Socket.SetDevice(Device))); @@ -204,14 +178,11 @@ public void SetInvalidDeviceTest() [Fact] public void SetDeviceOtherException() { - string[] requests = new string[] - { - "host:transport:169.254.109.177:5555" - }; + string[] requests = ["host:transport:169.254.109.177:5555"]; _ = Assert.Throws(() => RunTest( - new AdbResponse[] { AdbResponse.FromError("Too many cats.") }, + [AdbResponse.FromError("Too many cats.")], NoResponseMessages, requests, () => Socket.SetDevice(Device))); @@ -259,15 +230,8 @@ public void CreateSocketForwardTest() => [Fact] public void CreateDuplicateForwardTest() { - AdbResponse[] responses = new AdbResponse[] - { - AdbResponse.FromError("cannot rebind existing socket") - }; - - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:forward:norebind:tcp:1;tcp:2" - }; + AdbResponse[] responses = [AdbResponse.FromError("cannot rebind existing socket")]; + string[] requests = ["host-serial:169.254.109.177:5555:forward:norebind:tcp:1;tcp:2"]; _ = Assert.Throws(() => RunTest( @@ -283,10 +247,7 @@ public void CreateDuplicateForwardTest() [Fact] public void RemoveForwardTest() { - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:killforward:tcp:1" - }; + string[] requests = ["host-serial:169.254.109.177:5555:killforward:tcp:1"]; RunTest( OkResponse, @@ -301,17 +262,17 @@ public void RemoveForwardTest() [Fact] public void RemoveReverseForwardTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:killforward:localabstract:test" - }; + ]; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; RunTest( responses, @@ -326,10 +287,7 @@ public void RemoveReverseForwardTest() [Fact] public void RemoveAllForwardsTest() { - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:killforward-all" - }; + string[] requests = ["host-serial:169.254.109.177:5555:killforward-all"]; RunTest( OkResponse, @@ -344,17 +302,17 @@ public void RemoveAllForwardsTest() [Fact] public void RemoveAllReversesTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:killforward-all" - }; + ]; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; RunTest( responses, @@ -369,18 +327,10 @@ public void RemoveAllReversesTest() [Fact] public void ListForwardTest() { - string[] responseMessages = new string[] - { - "169.254.109.177:5555 tcp:1 tcp:2\n169.254.109.177:5555 tcp:3 tcp:4\n169.254.109.177:5555 tcp:5 local:/socket/1\n" - }; - - string[] requests = new string[] - { - "host-serial:169.254.109.177:5555:list-forward" - }; + string[] responseMessages = ["169.254.109.177:5555 tcp:1 tcp:2\n169.254.109.177:5555 tcp:3 tcp:4\n169.254.109.177:5555 tcp:5 local:/socket/1\n"]; + string[] requests = ["host-serial:169.254.109.177:5555:list-forward"]; ForwardData[] forwards = null; - RunTest( OkResponse, responseMessages, @@ -400,24 +350,21 @@ public void ListForwardTest() [Fact] public void ListReverseForwardTest() { - string[] responseMessages = new string[] - { - "(reverse) localabstract:scrcpy tcp:100\n(reverse) localabstract: scrcpy2 tcp:100\n(reverse) localabstract: scrcpy3 tcp:100\n" - }; - AdbResponse[] responses = new AdbResponse[] - { + string[] responseMessages = ["(reverse) localabstract:scrcpy tcp:100\n(reverse) localabstract: scrcpy2 tcp:100\n(reverse) localabstract: scrcpy3 tcp:100\n"]; + + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK, - }; + ]; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reverse:list-forward" - }; + ]; ForwardData[] forwards = null; - RunTest( responses, responseMessages, @@ -443,19 +390,19 @@ public void ExecuteRemoteCommandTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:echo Hello, World" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Hello, World\r\n"); using MemoryStream shellStream = new(streamData); @@ -484,19 +431,19 @@ public void ExecuteRemoteCommandUnresponsiveTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:echo Hello, World" - }; + ]; ConsoleOutputReceiver receiver = new(); @@ -544,8 +491,12 @@ public void GetFrameBufferTest() Framebuffer framebuffer = null; - Factories.AdbSocketFactory = (endPoint) => socket; - framebuffer = TestClient.GetFrameBuffer(device); + using (FactoriesLocker locker = FactoriesLocker.Wait()) + { + Factories.AdbSocketFactory = (endPoint) => socket; + framebuffer = TestClient.GetFrameBuffer(device); + Factories.Reset(); + } Assert.NotNull(framebuffer); Assert.Equal(device, framebuffer.Device); @@ -596,25 +547,25 @@ public void RunLogServiceTest() State = DeviceState.Online }; - AdbResponse[] responses = new AdbResponse[] - { + AdbResponse[] responses = + [ AdbResponse.OK, AdbResponse.OK - }; + ]; - string[] responseMessages = Array.Empty(); + string[] responseMessages = []; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "shell:logcat -B -b system" - }; + ]; ConsoleOutputReceiver receiver = new(); using Stream stream = File.OpenRead("Assets/logcat.bin"); using ShellStream shellStream = new(stream, false); - Collection logs = new(); + Collection logs = []; Action sink = logs.Add; RunTest( @@ -633,14 +584,14 @@ public void RunLogServiceTest() [Fact] public void RebootTest() { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", "reboot:" - }; + ]; RunTest( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, () => TestClient.Reboot(Device)); @@ -784,8 +735,8 @@ public void ConnectHostEndpointNullTest() => [Fact] public void DisconnectTest() { - string[] requests = new string[] { "host:disconnect:localhost:5555" }; - string[] responseMessages = new string[] { "disconnected 127.0.0.1:5555" }; + string[] requests = ["host:disconnect:localhost:5555"]; + string[] responseMessages = ["disconnected 127.0.0.1:5555"]; RunTest( OkResponse, @@ -806,11 +757,11 @@ public void RootTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "root:" - }; + ]; byte[] expectedData = new byte[1024]; byte[] expectedString = Encoding.UTF8.GetBytes("adbd cannot run as root in production builds\n"); @@ -818,12 +769,12 @@ public void RootTest() _ = Assert.Throws(() => RunTest( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { expectedData }, + [expectedData], Array.Empty(), () => TestClient.Root(device))); } @@ -840,11 +791,11 @@ public void UnrootTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "unroot:" - }; + ]; byte[] expectedData = new byte[1024]; byte[] expectedString = Encoding.UTF8.GetBytes("adbd not running as root\n"); @@ -852,12 +803,12 @@ public void UnrootTest() _ = Assert.Throws(() => RunTest( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { expectedData }, + [expectedData], Array.Empty(), () => TestClient.Unroot(device))); } @@ -874,14 +825,14 @@ public void InstallTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install' -S 205774" - }; + ]; // The app data is sent in chunks of 32 kb - Collection applicationDataChuncks = new(); + Collection applicationDataChunks = []; using (Stream stream = File.OpenRead("Assets/testapp.apk")) { @@ -897,7 +848,7 @@ public void InstallTest() else { buffer = buffer.Take(read).ToArray(); - applicationDataChuncks.Add(buffer); + applicationDataChunks.Add(buffer); } } } @@ -907,17 +858,13 @@ public void InstallTest() using (Stream stream = File.OpenRead("Assets/testapp.apk")) { RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { response }, - applicationDataChuncks.ToArray(), + [response], + applicationDataChunks.ToArray(), () => TestClient.Install(device, stream)); } } @@ -934,23 +881,18 @@ public void InstallCreateTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-create' -p com.google.android.gms" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Success: created install session [936013062]\r\n"); using MemoryStream shellStream = new(streamData); string session = string.Empty; - RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -971,14 +913,14 @@ public void InstallWriteTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-write' -S 205774 936013062 base.apk" - }; + ]; // The app data is sent in chunks of 32 kb - Collection applicationDataChuncks = new(); + Collection applicationDataChunks = []; using (Stream stream = File.OpenRead("Assets/testapp.apk")) { @@ -994,7 +936,7 @@ public void InstallWriteTest() else { buffer = buffer.Take(read).ToArray(); - applicationDataChuncks.Add(buffer); + applicationDataChunks.Add(buffer); } } } @@ -1004,17 +946,13 @@ public void InstallWriteTest() using (Stream stream = File.OpenRead("Assets/testapp.apk")) { RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, Array.Empty<(SyncCommand, string)>(), Array.Empty(), - new byte[][] { response }, - applicationDataChuncks.ToArray(), + [response], + applicationDataChunks.ToArray(), () => TestClient.InstallWrite(device, stream, "base", "936013062")); } } @@ -1031,21 +969,17 @@ public void InstallCommitTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "exec:cmd package 'install-commit' 936013062" - }; + ]; byte[] streamData = Encoding.ASCII.GetBytes("Success\r\n"); using MemoryStream shellStream = new(streamData); RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1064,23 +998,12 @@ public void GetFeatureSetTest() State = DeviceState.Online }; - string[] requests = new string[] - { - "host-serial:009d1cd696d5194a:features" - }; - - string[] responses = new string[] - { - "sendrecv_v2_brotli,remount_shell,sendrecv_v2,abb_exec,fixed_push_mkdir,fixed_push_symlink_timestamp,abb,shell_v2,cmd,ls_v2,apex,stat_v2\r\n" - }; + string[] requests = ["host-serial:009d1cd696d5194a:features"]; + string[] responses = ["sendrecv_v2_brotli,remount_shell,sendrecv_v2,abb_exec,fixed_push_mkdir,fixed_push_symlink_timestamp,abb,shell_v2,cmd,ls_v2,apex,stat_v2\r\n"]; IEnumerable features = null; - RunTest( - new AdbResponse[] - { - AdbResponse.OK, - }, + [AdbResponse.OK], responses, requests, () => features = TestClient.GetFeatureSet(device)); @@ -1102,11 +1025,11 @@ public void DumpScreenStringTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); string cleanDump = File.ReadAllText(@"Assets/dumpscreen_clean.txt"); @@ -1114,13 +1037,8 @@ public void DumpScreenStringTest() using MemoryStream shellStream = new(streamData); string xml = string.Empty; - RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1141,11 +1059,11 @@ public void DumpScreenStringMIUITest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string miuidump = File.ReadAllText(@"Assets/dumpscreen_miui.txt"); string cleanMIUIDump = File.ReadAllText(@"Assets/dumpscreen_miui_clean.txt"); @@ -1153,13 +1071,8 @@ public void DumpScreenStringMIUITest() using MemoryStream miuiStream = new(miuiStreamData); string miuiXml = string.Empty; - RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, miuiStream, @@ -1180,26 +1093,22 @@ public void DumpScreenStringEmptyTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; byte[] emptyStreamData = Encoding.UTF8.GetBytes(string.Empty); using MemoryStream emptyStream = new(emptyStreamData); - string emptyXml = string.Empty; + string emptyXml = string.Empty; RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, - NoResponseMessages, - requests, - emptyStream, - () => emptyXml = TestClient.DumpScreenString(device)); + [AdbResponse.OK, AdbResponse.OK], + NoResponseMessages, + requests, + emptyStream, + () => emptyXml = TestClient.DumpScreenString(device)); Assert.True(string.IsNullOrEmpty(emptyXml)); } @@ -1216,11 +1125,11 @@ public void DumpScreenStringErrorTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string errorXml = File.ReadAllText(@"Assets/dumpscreen_error.txt"); byte[] errorStreamData = Encoding.UTF8.GetBytes(errorXml); @@ -1228,15 +1137,11 @@ public void DumpScreenStringErrorTest() Assert.Throws(() => RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, - NoResponseMessages, - requests, - errorStream, - () => TestClient.DumpScreenString(device))); + [AdbResponse.OK, AdbResponse.OK], + NoResponseMessages, + requests, + errorStream, + () => TestClient.DumpScreenString(device))); } /// @@ -1251,24 +1156,19 @@ public void DumpScreenTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); using MemoryStream shellStream = new(streamData); XmlDocument xml = null; - RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1293,11 +1193,11 @@ public void ClickTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:input tap 100 100" - }; + ]; byte[] streamData = Encoding.UTF8.GetBytes(@"java.lang.SecurityException: Injecting to another application requires INJECT_EVENTS permission at android.os.Parcel.createExceptionOrNull(Parcel.java:2373) @@ -1325,11 +1225,7 @@ at android.os.Binder.execTransactInternal(Binder.java:1165) JavaException exception = Assert.Throws(() => RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1372,22 +1268,18 @@ public void ClickCordsTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:input tap 100 100" - }; + ]; byte[] streamData = Encoding.UTF8.GetBytes(@"Error: Injecting to another application requires INJECT_EVENTS permission"); using MemoryStream shellStream = new(streamData); _ = Assert.Throws(() => RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1406,22 +1298,18 @@ public void FindElementTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); using MemoryStream shellStream = new(streamData); RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1447,22 +1335,18 @@ public void FindElementsTest() State = DeviceState.Online }; - string[] requests = new string[] - { + string[] requests = + [ "host:transport:009d1cd696d5194a", "shell:uiautomator dump /dev/tty" - }; + ]; string dump = File.ReadAllText(@"Assets/dumpscreen.txt"); byte[] streamData = Encoding.UTF8.GetBytes(dump); using MemoryStream shellStream = new(streamData); RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - }, + [AdbResponse.OK, AdbResponse.OK], NoResponseMessages, requests, shellStream, @@ -1480,15 +1364,8 @@ public void FindElementsTest() private void RunConnectTest(Action test, string connectString) { - string[] requests = new string[] - { - $"host:connect:{connectString}" - }; - - string[] responseMessages = new string[] - { - $"connected to {connectString}" - }; + string[] requests = [$"host:connect:{connectString}"]; + string[] responseMessages = [$"connected to {connectString}"]; RunTest( OkResponse, @@ -1499,15 +1376,8 @@ private void RunConnectTest(Action test, string connectString) private void RunPairTest(Action test, string connectString, string code) { - string[] requests = new string[] - { - $"host:pair:{code}:{connectString}" - }; - - string[] responseMessages = new string[] - { - $"Successfully paired to {connectString} [guid=adb-996198a3-xPRwsQ]" - }; + string[] requests = [$"host:pair:{code}:{connectString}"]; + string[] responseMessages = [$"Successfully paired to {connectString} [guid=adb-996198a3-xPRwsQ]"]; RunTest( OkResponse, @@ -1518,44 +1388,26 @@ private void RunPairTest(Action test, string connectString, string code) private void RunCreateReverseTest(Action test, string reverseString) { - string[] requests = new string[] - { + string[] requests = + [ "host:transport:169.254.109.177:5555", $"reverse:forward:{reverseString}", - }; + ]; RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK, - AdbResponse.OK - }, - new string[] - { - null - }, + [AdbResponse.OK, AdbResponse.OK, AdbResponse.OK], + [null], requests, () => test(Device)); } private void RunCreateForwardTest(Action test, string forwardString) { - string[] requests = new string[] - { - $"host-serial:169.254.109.177:5555:forward:{forwardString}" - }; + string[] requests = [$"host-serial:169.254.109.177:5555:forward:{forwardString}"]; RunTest( - new AdbResponse[] - { - AdbResponse.OK, - AdbResponse.OK - }, - new string[] - { - null - }, + [AdbResponse.OK, AdbResponse.OK], + [null], requests, () => test(Device)); } diff --git a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.Async.cs b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.Async.cs index 6430112b..ff6a965c 100644 --- a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.Async.cs @@ -13,7 +13,6 @@ public async void GetVersionAsyncTest() { Version = new Version(1, 0, 32) }; - Assert.Equal(new Version(1, 0, 32), await commandLine.GetVersionAsync()); } @@ -34,7 +33,6 @@ public async void GetOutdatedVersionAsyncTest() { Version = new Version(1, 0, 1) }; - _ = await Assert.ThrowsAsync(() => commandLine.GetVersionAsync()); } diff --git a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs index 74d33fcb..103592f8 100644 --- a/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbCommandLineClientTests.cs @@ -16,7 +16,6 @@ public void GetVersionTest() { Version = new Version(1, 0, 32) }; - Assert.Equal(new Version(1, 0, 32), commandLine.GetVersion()); } @@ -37,7 +36,6 @@ public void GetOutdatedVersionTest() { Version = new Version(1, 0, 1) }; - _ = Assert.Throws(commandLine.GetVersion); } diff --git a/AdvancedSharpAdbClient.Tests/AdbSocketTests.Async.cs b/AdvancedSharpAdbClient.Tests/AdbSocketTests.Async.cs index 8d650767..cedda4d1 100644 --- a/AdvancedSharpAdbClient.Tests/AdbSocketTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/AdbSocketTests.Async.cs @@ -14,23 +14,23 @@ public partial class AdbSocketTests public async void SendSyncDATARequestAsyncTest() => await RunTestAsync( (socket) => socket.SendSyncRequestAsync(SyncCommand.DATA, 2, CancellationToken.None), - new byte[] { (byte)'D', (byte)'A', (byte)'T', (byte)'A', 2, 0, 0, 0 }); + [(byte)'D', (byte)'A', (byte)'T', (byte)'A', 2, 0, 0, 0]); [Fact] public async void SendSyncSENDRequestAsyncTest() => await RunTestAsync( (socket) => socket.SendSyncRequestAsync(SyncCommand.SEND, "/test", CancellationToken.None), - new byte[] { (byte)'S', (byte)'E', (byte)'N', (byte)'D', 5, 0, 0, 0, (byte)'/', (byte)'t', (byte)'e', (byte)'s', (byte)'t' }); + [(byte)'S', (byte)'E', (byte)'N', (byte)'D', 5, 0, 0, 0, (byte)'/', (byte)'t', (byte)'e', (byte)'s', (byte)'t']); [Fact] public async void SendSyncDENTRequestAsyncTest() => await RunTestAsync( (socket) => socket.SendSyncRequestAsync(SyncCommand.DENT, "/data", 633, CancellationToken.None), - new byte[] { (byte)'D', (byte)'E', (byte)'N', (byte)'T', 9, 0, 0, 0, (byte)'/', (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)',', (byte)'6', (byte)'3', (byte)'3' }); + [(byte)'D', (byte)'E', (byte)'N', (byte)'T', 9, 0, 0, 0, (byte)'/', (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)',', (byte)'6', (byte)'3', (byte)'3']); [Fact] public async void SendSyncNullRequestAsyncTest() => - _ = await Assert.ThrowsAsync(() => RunTestAsync((socket) => socket.SendSyncRequestAsync(SyncCommand.DATA, null, CancellationToken.None), Array.Empty())); + _ = await Assert.ThrowsAsync(() => RunTestAsync((socket) => socket.SendSyncRequestAsync(SyncCommand.DATA, null, CancellationToken.None), [])); [Fact] public async void ReadSyncResponseAsync() @@ -117,7 +117,7 @@ public async void ReadAsyncTest() data[i] = (byte)i; } - await tcpSocket.InputStream.WriteAsync(data, 0, 101); + await tcpSocket.InputStream.WriteAsync(data.AsMemory(0, 101)); tcpSocket.InputStream.Position = 0; // Buffer has a capacity of 101, but we'll only want to read 100 bytes diff --git a/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs b/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs index a6b11ba9..c5f6170a 100644 --- a/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbSocketTests.cs @@ -50,23 +50,23 @@ public void IsOkayTest() public void SendSyncDATARequestTest() => RunTest( (socket) => socket.SendSyncRequest(SyncCommand.DATA, 2), - new byte[] { (byte)'D', (byte)'A', (byte)'T', (byte)'A', 2, 0, 0, 0 }); + [(byte)'D', (byte)'A', (byte)'T', (byte)'A', 2, 0, 0, 0]); [Fact] public void SendSyncSENDRequestTest() => RunTest( (socket) => socket.SendSyncRequest(SyncCommand.SEND, "/test"), - new byte[] { (byte)'S', (byte)'E', (byte)'N', (byte)'D', 5, 0, 0, 0, (byte)'/', (byte)'t', (byte)'e', (byte)'s', (byte)'t' }); + [(byte)'S', (byte)'E', (byte)'N', (byte)'D', 5, 0, 0, 0, (byte)'/', (byte)'t', (byte)'e', (byte)'s', (byte)'t']); [Fact] public void SendSyncDENTRequestTest() => RunTest( (socket) => socket.SendSyncRequest(SyncCommand.DENT, "/data", 633), - new byte[] { (byte)'D', (byte)'E', (byte)'N', (byte)'T', 9, 0, 0, 0, (byte)'/', (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)',', (byte)'6', (byte)'3', (byte)'3' }); + [(byte)'D', (byte)'E', (byte)'N', (byte)'T', 9, 0, 0, 0, (byte)'/', (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)',', (byte)'6', (byte)'3', (byte)'3']); [Fact] public void SendSyncNullRequestTest() => - _ = Assert.Throws(() => RunTest((socket) => socket.SendSyncRequest(SyncCommand.DATA, null), Array.Empty())); + _ = Assert.Throws(() => RunTest((socket) => socket.SendSyncRequest(SyncCommand.DATA, null), [])); [Fact] public void ReadSyncResponse() diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs index 8d5487a4..7c013e47 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.Async.cs @@ -21,6 +21,8 @@ public async void StatAsyncTest() ISyncService mock = Substitute.For(); mock.StatAsync("/test", Arg.Any()).Returns(tcs.Task); + using FactoriesLocker locker = await FactoriesLocker.WaitAsync(); + Factories.SyncServiceFactory = (c, d) => mock; DeviceData device = new(); diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.cs index 1d4978c7..b155e6a6 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/DeviceExtensionsTests.cs @@ -20,6 +20,8 @@ public void StatTest() ISyncService mock = Substitute.For(); mock.Stat("/test").Returns(stats); + using FactoriesLocker locker = FactoriesLocker.Wait(); + Factories.SyncServiceFactory = (c, d) => mock; DeviceData device = new(); diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs index 209b8f2c..381b856a 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs @@ -37,6 +37,8 @@ public async void InstallPackageAsyncTest() { DummySyncService syncService = new(); + using FactoriesLocker locker = await FactoriesLocker.WaitAsync(); + Factories.SyncServiceFactory = (c, d) => syncService; DummyAdbClient adbClient = new(); @@ -123,6 +125,8 @@ public async void InstallMultiplePackageAsyncTest() { DummySyncService syncService = new(); + using FactoriesLocker locker = await FactoriesLocker.WaitAsync(); + Factories.SyncServiceFactory = (c, d) => syncService; DummyAdbClient adbClient = new(); diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs index 5e7a5381..3710528d 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs @@ -66,6 +66,8 @@ public void InstallPackageTest() { DummySyncService syncService = new(); + using FactoriesLocker locker = FactoriesLocker.Wait(); + Factories.SyncServiceFactory = (c, d) => syncService; DummyAdbClient adbClient = new(); @@ -104,7 +106,7 @@ public void InstallMultipleRemotePackageTest() adbClient.Commands["pm install-write 936013062 base.apk \"/data/base.apk\""] = "Success"; adbClient.Commands["pm install-write 936013062 splitapp0.apk \"/data/split-dpi.apk\""] = "Success"; adbClient.Commands["pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\""] = "Success"; - adbClient.Commands["pm install-commit 936013062"] = "Success" ; + adbClient.Commands["pm install-commit 936013062"] = "Success"; DeviceData device = new() { @@ -152,6 +154,8 @@ public void InstallMultiplePackageTest() { DummySyncService syncService = new(); + using FactoriesLocker locker = FactoriesLocker.Wait(); + Factories.SyncServiceFactory = (c, d) => syncService; DummyAdbClient adbClient = new(); diff --git a/AdvancedSharpAdbClient.Tests/Dummys/DeviceMonitorSink.cs b/AdvancedSharpAdbClient.Tests/Dummys/DeviceMonitorSink.cs index 884e7e3c..57bbe1db 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/DeviceMonitorSink.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/DeviceMonitorSink.cs @@ -14,10 +14,10 @@ public DeviceMonitorSink(DeviceMonitor monitor) Monitor.DeviceConnected += OnDeviceConnected; Monitor.DeviceDisconnected += OnDeviceDisconnected; - ChangedEvents = new Collection(); - NotifiedEvents = new Collection(); - ConnectedEvents = new Collection(); - DisconnectedEvents = new Collection(); + ChangedEvents = []; + NotifiedEvents = []; + ConnectedEvents = []; + DisconnectedEvents = []; } public void ResetSignals() diff --git a/AdvancedSharpAdbClient.Tests/Dummys/DummyTcpSocket.cs b/AdvancedSharpAdbClient.Tests/Dummys/DummyTcpSocket.cs index 6d388205..3be32d3b 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/DummyTcpSocket.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/DummyTcpSocket.cs @@ -26,6 +26,7 @@ internal class DummyTcpSocket : ITcpSocket public void Close() => Connected = false; public void Connect(EndPoint endPoint) => Connected = true; + public Task ConnectAsync(EndPoint endPoint) { Connected = true; diff --git a/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs b/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs index 936ad99d..c6c8c0aa 100644 --- a/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs +++ b/AdvancedSharpAdbClient.Tests/Dummys/TracingAdbSocket.cs @@ -10,12 +10,8 @@ namespace AdvancedSharpAdbClient.Tests { - internal class TracingAdbSocket : AdbSocket, IDummyAdbSocket + internal class TracingAdbSocket(EndPoint endPoint) : AdbSocket(endPoint), IDummyAdbSocket { - public TracingAdbSocket(EndPoint endPoint) : base(endPoint) - { - } - public Stream ShellStream { get; set; } public bool DoDispose { get; set; } diff --git a/AdvancedSharpAdbClient.Tests/Extensions/FactoriesLocker.cs b/AdvancedSharpAdbClient.Tests/Extensions/FactoriesLocker.cs new file mode 100644 index 00000000..c04988f2 --- /dev/null +++ b/AdvancedSharpAdbClient.Tests/Extensions/FactoriesLocker.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace AdvancedSharpAdbClient.Tests +{ + /// + /// Locker for the class. + /// + public class FactoriesLocker : IDisposable + { + public static SemaphoreSlim SlimLocker { get; } = new(1, 1); + + public static FactoriesLocker Wait() + { + SlimLocker.Wait(); + return new FactoriesLocker(); + } + + public static async Task WaitAsync() + { + await SlimLocker.WaitAsync(); + return new FactoriesLocker(); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + SlimLocker.Release(); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs b/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs index 1af7da56..325a6753 100644 --- a/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs +++ b/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs @@ -28,7 +28,7 @@ public void IsNullOrWhiteSpaceTest() [Fact] public void JoinTest() => - Assert.Equal("Hello World!", Utilities.Join(" ", new string[] { "Hello", "World!" })); + Assert.Equal("Hello World!", Utilities.Join(" ", ["Hello", "World!"])); [Fact] public void FromUnixTimeSecondsTest() diff --git a/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs b/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs index 09a47fcc..13a2bff3 100644 --- a/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs +++ b/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Text; -using System.Threading.Tasks; using Xunit; namespace AdvancedSharpAdbClient.Logs.Tests diff --git a/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs b/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs index e0d25840..a07615c3 100644 --- a/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/FramebufferTests.cs @@ -46,8 +46,12 @@ public void RefreshTest() using Framebuffer framebuffer = new(device); - Factories.AdbSocketFactory = (endPoint) => socket; - framebuffer.Refresh(); + using (FactoriesLocker locker = FactoriesLocker.Wait()) + { + Factories.AdbSocketFactory = (endPoint) => socket; + framebuffer.Refresh(); + Factories.Reset(); + } Assert.NotNull(framebuffer); Assert.Equal(device, framebuffer.Device); @@ -109,8 +113,12 @@ public async void RefreshAsyncTest() using Framebuffer framebuffer = new(device); - Factories.AdbSocketFactory = (endPoint) => socket; - await framebuffer.RefreshAsync(); + using (FactoriesLocker locker = await FactoriesLocker.WaitAsync()) + { + Factories.AdbSocketFactory = (endPoint) => socket; + await framebuffer.RefreshAsync(); + Factories.Reset(); + } Assert.NotNull(framebuffer); Assert.Equal(device, framebuffer.Device); diff --git a/AdvancedSharpAdbClient.Tests/SocketBasedTests.cs b/AdvancedSharpAdbClient.Tests/SocketBasedTests.cs index f025d646..dcac2be8 100644 --- a/AdvancedSharpAdbClient.Tests/SocketBasedTests.cs +++ b/AdvancedSharpAdbClient.Tests/SocketBasedTests.cs @@ -15,6 +15,8 @@ public class SocketBasedTests protected SocketBasedTests(bool integrationTest, bool doDispose) { + using FactoriesLocker locker = FactoriesLocker.Wait(); + // this.EndPoint = AdbClient.Instance.EndPoint; #if DEBUG // Use the tracing adb socket factory to run the tests on an actual device. @@ -46,9 +48,9 @@ protected SocketBasedTests(bool integrationTest, bool doDispose) Factories.Reset(); } - protected static AdbResponse[] NoResponses { get; } = Array.Empty(); - protected static AdbResponse[] OkResponse { get; } = new AdbResponse[] { AdbResponse.OK }; - protected static string[] NoResponseMessages { get; } = Array.Empty(); + protected static AdbResponse[] NoResponses { get; } = []; + protected static AdbResponse[] OkResponse { get; } = [AdbResponse.OK]; + protected static string[] NoResponseMessages { get; } = []; protected static DeviceData Device { get; } = new() { Serial = "169.254.109.177:5555", diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs index 5aed6b66..1337dc61 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs @@ -25,8 +25,8 @@ await RunTestAsync( NoResponseMessages, Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello"), - new SyncCommand[] { SyncCommand.STAT }, - new byte[][] { new byte[] { 160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0 } }, + new[] { SyncCommand.STAT }, + new byte[][] { [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0] }, null, async () => { @@ -56,13 +56,13 @@ await RunTestAsync( ResponseMessages(".", "..", "sdcard0", "emulated"), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.LIST, "/storage"), - new SyncCommand[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, + new[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, new byte[][] { - new byte[] { 233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 } + [233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], + [237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], + [255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86], + [109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86] }, null, async () => @@ -121,7 +121,7 @@ await RunTestAsync( new SyncCommand[] { SyncCommand.STAT, SyncCommand.DATA, SyncCommand.DONE }, new byte[][] { - new byte[] { 160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0 }, + [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0], contentLength, content }, @@ -147,10 +147,12 @@ public async void PushAsyncTest() Stream stream = File.OpenRead("Assets/fstab.bin"); byte[] content = File.ReadAllBytes("Assets/fstab.bin"); - List contentMessage = new(); - contentMessage.AddRange(SyncCommandConverter.GetBytes(SyncCommand.DATA)); - contentMessage.AddRange(BitConverter.GetBytes(content.Length)); - contentMessage.AddRange(content); + List contentMessage = + [ + .. SyncCommandConverter.GetBytes(SyncCommand.DATA), + .. BitConverter.GetBytes(content.Length), + .. content, + ]; await RunTestAsync( OkResponses(2), @@ -159,11 +161,11 @@ await RunTestAsync( SyncRequests( SyncCommand.SEND, "/sdcard/test,644", SyncCommand.DONE, "1446505200"), - new SyncCommand[] { SyncCommand.OKAY }, + new[] { SyncCommand.OKAY }, null, new byte[][] { - contentMessage.ToArray() + [.. contentMessage] }, async () => { diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs index 42589feb..56582c2f 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs @@ -36,8 +36,8 @@ public void StatTest() NoResponseMessages, Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello"), - new SyncCommand[] { SyncCommand.STAT }, - new byte[][] { new byte[] { 160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0 } }, + new[] { SyncCommand.STAT }, + new byte[][] { [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0] }, null, () => { @@ -67,13 +67,13 @@ public void GetListingTest() ResponseMessages(".", "..", "sdcard0", "emulated"), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.LIST, "/storage"), - new SyncCommand[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, + new[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, new byte[][] { - new byte[] { 233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86 }, - new byte[] { 109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86 } + [233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], + [237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], + [255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86], + [109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86] }, null, () => @@ -129,13 +129,12 @@ public void PullTest() ResponseMessages(), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello").Union(SyncRequests(SyncCommand.RECV, "/fstab.donatello")), - new SyncCommand[] { SyncCommand.STAT, SyncCommand.DATA, SyncCommand.DONE }, - new byte[][] - { - new byte[] { 160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0 }, + [SyncCommand.STAT, SyncCommand.DATA, SyncCommand.DONE], + [ + [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0], contentLength, content - }, + ], null, () => { @@ -158,10 +157,12 @@ public void PushTest() Stream stream = File.OpenRead("Assets/fstab.bin"); byte[] content = File.ReadAllBytes("Assets/fstab.bin"); - List contentMessage = new(); - contentMessage.AddRange(SyncCommandConverter.GetBytes(SyncCommand.DATA)); - contentMessage.AddRange(BitConverter.GetBytes(content.Length)); - contentMessage.AddRange(content); + List contentMessage = + [ + .. SyncCommandConverter.GetBytes(SyncCommand.DATA), + .. BitConverter.GetBytes(content.Length), + .. content, + ]; RunTest( OkResponses(2), @@ -170,12 +171,9 @@ public void PushTest() SyncRequests( SyncCommand.SEND, "/sdcard/test,644", SyncCommand.DONE, "1446505200"), - new SyncCommand[] { SyncCommand.OKAY }, + [SyncCommand.OKAY], null, - new byte[][] - { - contentMessage.ToArray() - }, + [[.. contentMessage]], () => { using SyncService service = new(Socket, device); From 9d22002afd41f6e9ec1be5f9e26b74c02a159854 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Fri, 22 Sep 2023 17:43:37 +0800 Subject: [PATCH 2/9] Update AdvancedSharpAdbClient C# version --- AdvancedSharpAdbClient/AdbClient.Async.cs | 34 ++++++++---------- AdvancedSharpAdbClient/AdbClient.cs | 36 +++++++++---------- .../AdbCommandLineClient.Async.cs | 2 +- .../AdbCommandLineClient.cs | 2 +- AdvancedSharpAdbClient/AdbServer.cs | 19 +++------- AdvancedSharpAdbClient/AdbSocket.cs | 2 +- .../DeviceCommands/DeviceExtensions.Async.cs | 8 ++--- .../DeviceCommands/DeviceExtensions.cs | 4 +-- .../DeviceCommands/PackageManager.Async.cs | 8 ++--- .../DeviceCommands/PackageManager.cs | 6 ++-- AdvancedSharpAdbClient/DeviceMonitor.cs | 2 +- .../Extensions/SyncCommandConverter.cs | 2 +- .../Extensions/Utilities.cs | 15 ++++++++ .../Logs/AndroidLogEntry.cs | 2 +- .../Logs/LogReader.Async.cs | 2 +- AdvancedSharpAdbClient/Logs/LogReader.cs | 2 +- AdvancedSharpAdbClient/Models/ForwardData.cs | 2 +- AdvancedSharpAdbClient/SyncService.Async.cs | 2 +- Directory.Build.props | 11 +++++- 19 files changed, 85 insertions(+), 76 deletions(-) diff --git a/AdvancedSharpAdbClient/AdbClient.Async.cs b/AdvancedSharpAdbClient/AdbClient.Async.cs index c3c6bbe9..5ac7d873 100644 --- a/AdvancedSharpAdbClient/AdbClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbClient.Async.cs @@ -51,7 +51,7 @@ public async Task> GetDevicesAsync(CancellationToken can await socket.ReadAdbResponseAsync(cancellationToken); string reply = await socket.ReadStringAsync(cancellationToken); - string[] data = reply.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + string[] data = reply.Split(separator, StringSplitOptions.RemoveEmptyEntries); return data.Select(DeviceData.CreateFromAdbData); } @@ -149,7 +149,7 @@ public async Task> ListForwardAsync(DeviceData device, string data = await socket.ReadStringAsync(cancellationToken); - string[] parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); return parts.Select(ForwardData.FromString); } @@ -167,7 +167,7 @@ public async Task> ListReverseForwardAsync(DeviceData d string data = await socket.ReadStringAsync(cancellationToken); - string[] parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); return parts.Select(ForwardData.FromString); } @@ -235,7 +235,7 @@ public async Task GetFrameBufferAsync(DeviceData device, Cancellati /// public Task RunLogServiceAsync(DeviceData device, Action messageSink, params LogId[] logNames) => RunLogServiceAsync(device, messageSink, default, logNames); - + /// public async Task RunLogServiceAsync(DeviceData device, Action messageSink, CancellationToken cancellationToken, params LogId[] logNames) { @@ -262,7 +262,7 @@ public async Task RunLogServiceAsync(DeviceData device, Action message #if NETCOREAPP3_0_OR_GREATER await #endif - using Stream stream = socket.GetShellStream(); + using Stream stream = socket.GetShellStream(); LogReader reader = new(stream); while (!cancellationToken.IsCancellationRequested) @@ -564,8 +564,8 @@ public async Task InstallCreateAsync(DeviceData device, string packageNa throw new AdbException(await reader.ReadToEndAsync(cancellationToken)); } - int arr = result.IndexOf("]") - 1 - result.IndexOf("["); - string session = result.Substring(result.IndexOf("[") + 1, arr); + int arr = result.IndexOf(']') - 1 - result.IndexOf('['); + string session = result.Substring(result.IndexOf('[') + 1, arr); return session; } @@ -649,7 +649,7 @@ public async Task> GetFeatureSetAsync(DeviceData device, Can AdbResponse response = await socket.ReadAdbResponseAsync(cancellationToken); string features = await socket.ReadStringAsync(cancellationToken); - IEnumerable featureList = features.Trim().Split(new char[] { '\n', ',' }); + IEnumerable featureList = features.Trim().Split('\n', ','); return featureList; } @@ -671,11 +671,7 @@ public async Task DumpScreenStringAsync(DeviceData device, CancellationT return xmlString; } Match xmlMatch = GetXMLRegex().Match(xmlString); - if (!xmlMatch.Success) - { - throw new XmlException("An error occurred while receiving xml: " + xmlString); - } - return xmlMatch.Value; + return !xmlMatch.Success ? throw new XmlException("An error occurred while receiving xml: " + xmlString) : xmlMatch.Value; } /// @@ -721,7 +717,7 @@ public async Task ClickAsync(DeviceData device, Cords cords, CancellationToken c { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -742,7 +738,7 @@ public async Task ClickAsync(DeviceData device, int x, int y, CancellationToken { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -763,7 +759,7 @@ public async Task SwipeAsync(DeviceData device, Element first, Element second, l { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -784,7 +780,7 @@ public async Task SwipeAsync(DeviceData device, int x1, int y1, int x2, int y2, { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -958,7 +954,7 @@ public async Task SendKeyEventAsync(DeviceData device, string key, CancellationT { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new InvalidKeyEventException("KeyEvent is invalid"); } @@ -979,7 +975,7 @@ public async Task SendTextAsync(DeviceData device, string text, CancellationToke { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new InvalidTextException(); } diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index 60b18d81..b7d5bb53 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -3,18 +3,18 @@ // using AdvancedSharpAdbClient.Exceptions; +using AdvancedSharpAdbClient.Logs; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using AdvancedSharpAdbClient.Logs; using System.IO; using System.Linq; using System.Net; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Xml; -using System.Text.RegularExpressions; namespace AdvancedSharpAdbClient { @@ -33,6 +33,8 @@ namespace AdvancedSharpAdbClient /// public partial class AdbClient : IAdbClient { + private static readonly char[] separator = ['\r', '\n']; + /// /// The default port to use when connecting to a device over TCP/IP. /// @@ -193,7 +195,7 @@ public IEnumerable GetDevices() socket.ReadAdbResponse(); string reply = socket.ReadString(); - string[] data = reply.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + string[] data = reply.Split(separator, StringSplitOptions.RemoveEmptyEntries); return data.Select(DeviceData.CreateFromAdbData); } @@ -291,7 +293,7 @@ public IEnumerable ListForward(DeviceData device) string data = socket.ReadString(); - string[] parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); return parts.Select(ForwardData.FromString); } @@ -309,7 +311,7 @@ public IEnumerable ListReverseForward(DeviceData device) string data = socket.ReadString(); - string[] parts = data.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); return parts.Select(ForwardData.FromString); } @@ -672,8 +674,8 @@ public string InstallCreate(DeviceData device, string packageName = null, params throw new AdbException(reader.ReadToEnd()); } - int arr = result.IndexOf("]") - 1 - result.IndexOf("["); - string session = result.Substring(result.IndexOf("[") + 1, arr); + int arr = result.IndexOf(']') - 1 - result.IndexOf('['); + string session = result.Substring(result.IndexOf('[') + 1, arr); return session; } @@ -755,7 +757,7 @@ public IEnumerable GetFeatureSet(DeviceData device) AdbResponse response = socket.ReadAdbResponse(); string features = socket.ReadString(); - IEnumerable featureList = features.Trim().Split(new char[] { '\n', ',' }); + IEnumerable featureList = features.Trim().Split('\n', ','); return featureList; } @@ -777,11 +779,7 @@ public string DumpScreenString(DeviceData device) return xmlString; } Match xmlMatch = GetXMLRegex().Match(xmlString); - if (!xmlMatch.Success) - { - throw new XmlException("An error occurred while receiving xml: " + xmlString); - } - return xmlMatch.Value; + return !xmlMatch.Success ? throw new XmlException("An error occurred while receiving xml: " + xmlString) : xmlMatch.Value; } /// @@ -827,7 +825,7 @@ public void Click(DeviceData device, Cords cords) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -848,7 +846,7 @@ public void Click(DeviceData device, int x, int y) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -869,7 +867,7 @@ public void Swipe(DeviceData device, Element first, Element second, long speed) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -890,7 +888,7 @@ public void Swipe(DeviceData device, int x1, int y1, int x2, int y2, long speed) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new ElementNotFoundException("Coordinates of element is invalid"); } @@ -1013,7 +1011,7 @@ public void SendKeyEvent(DeviceData device, string key) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new InvalidKeyEventException("KeyEvent is invalid"); } @@ -1034,7 +1032,7 @@ public void SendText(DeviceData device, string text) { throw JavaException.Parse(result); } - else if (result.IndexOf("ERROR", StringComparison.OrdinalIgnoreCase) != -1) // error or ERROR + else if (result.Contains("ERROR", StringComparison.OrdinalIgnoreCase)) // error or ERROR { throw new InvalidTextException(); } diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs index 8a58c5d2..609b68c3 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs @@ -22,7 +22,7 @@ public partial class AdbCommandLineClient public virtual async Task GetVersionAsync(CancellationToken cancellationToken = default) { // Run the adb.exe version command and capture the output. - List standardOutput = new(); + List standardOutput = []; await RunAdbProcessAsync("version", null, standardOutput, cancellationToken); diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.cs index 8cd435c8..5a8b8ed7 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.cs @@ -97,7 +97,7 @@ public AdbCommandLineClient(string adbPath, bool isForce = false public virtual Version GetVersion() { // Run the adb.exe version command and capture the output. - List standardOutput = new(); + List standardOutput = []; RunAdbProcess("version", null, standardOutput); diff --git a/AdvancedSharpAdbClient/AdbServer.cs b/AdvancedSharpAdbClient/AdbServer.cs index a08a9d72..db03ae1d 100644 --- a/AdvancedSharpAdbClient/AdbServer.cs +++ b/AdvancedSharpAdbClient/AdbServer.cs @@ -17,7 +17,9 @@ namespace AdvancedSharpAdbClient /// giant multiplexing loop whose purpose is to orchestrate the exchange of data /// between clients and devices. /// - public partial class AdbServer : IAdbServer + /// The current ADB client that manages the connection. + /// The to create . + public partial class AdbServer(IAdbClient adbClient, Func adbCommandLineClientFactory) : IAdbServer { /// /// The minimum version of adb.exe that is supported by this library. @@ -60,14 +62,14 @@ public partial class AdbServer : IAdbServer /// /// The current ADB client that manages the connection. /// - protected readonly IAdbClient adbClient; + protected readonly IAdbClient adbClient = adbClient ?? throw new ArgumentNullException(nameof(adbClient)); /// /// Gets or sets a function that returns a new instance of a class that implements the /// interface, that can be used to interact with the /// adb.exe command line client. /// - protected readonly Func adbCommandLineClientFactory; + protected readonly Func adbCommandLineClientFactory = adbCommandLineClientFactory ?? throw new ArgumentNullException(nameof(adbCommandLineClientFactory)); /// /// Initializes a new instance of the class. @@ -92,17 +94,6 @@ public AdbServer(Func adbCommandLineClientFactory { } - /// - /// Initializes a new instance of the class. - /// - /// The current ADB client that manages the connection. - /// The to create . - public AdbServer(IAdbClient adbClient, Func adbCommandLineClientFactory) - { - this.adbCommandLineClientFactory = adbCommandLineClientFactory ?? throw new ArgumentNullException(nameof(adbCommandLineClientFactory)); - this.adbClient = adbClient ?? throw new ArgumentNullException(nameof(adbClient)); - } - /// /// Gets or sets the default instance of the interface. /// diff --git a/AdvancedSharpAdbClient/AdbSocket.cs b/AdvancedSharpAdbClient/AdbSocket.cs index e8430f9e..ccb296bd 100644 --- a/AdvancedSharpAdbClient/AdbSocket.cs +++ b/AdvancedSharpAdbClient/AdbSocket.cs @@ -82,7 +82,7 @@ public AdbSocket(string host, int port DnsEndPoint endPoint = values.Length <= 0 ? throw new ArgumentNullException(nameof(host)) : new DnsEndPoint(values[0], values.Length > 1 && int.TryParse(values[1], out int _port) ? _port : port); - + socket = new TcpSocket(); socket.Connect(endPoint); socket.ReceiveBufferSize = ReceiveBufferSize; diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs index 2f2a74bf..6db9ea95 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.Async.cs @@ -69,7 +69,7 @@ public static async Task> List(this IAdbClient clien public static async Task PullAsync(this IAdbClient client, DeviceData device, string remotePath, Stream stream, EventHandler syncProgressEventHandler = null, - IProgress progress = null, CancellationToken cancellationToken = default ) + IProgress progress = null, CancellationToken cancellationToken = default) { using ISyncService service = Factories.SyncServiceFactory(client, device); if (syncProgressEventHandler != null) @@ -96,7 +96,7 @@ public static async Task PullAsync(this IAdbClient client, DeviceData device, public static async Task PushAsync(this IAdbClient client, DeviceData device, string remotePath, Stream stream, int permissions, DateTimeOffset timestamp, EventHandler syncProgressEventHandler = null, - IProgress progress = null, CancellationToken cancellationToken = default ) + IProgress progress = null, CancellationToken cancellationToken = default) { using ISyncService service = Factories.SyncServiceFactory(client, device); if (syncProgressEventHandler != null) @@ -200,7 +200,7 @@ public static async Task> ListProcessesAsync(this IA // The easiest way to do the directory listings would be to use the SyncService; unfortunately, // the sync service doesn't work very well with /proc/ so we're back to using ls and taking it // from there. - List processes = new(); + List processes = []; // List all processes by doing ls /proc/. // All subfolders which are completely numeric are PIDs @@ -224,7 +224,7 @@ await client.ExecuteShellCommandAsync(device, @"SDK=""$(/system/bin/getprop ro.b /system/bin/ls -1 /proc/ fi".Replace("\r\n", "\n"), receiver, cancellationToken); - Collection pids = new(); + Collection pids = []; string output = receiver.ToString(); using (StringReader reader = new(output)) diff --git a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs index e1d9f2e1..3f5090d3 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/DeviceExtensions.cs @@ -213,7 +213,7 @@ public static IEnumerable ListProcesses(this IAdbClient client, // The easiest way to do the directory listings would be to use the SyncService; unfortunately, // the sync service doesn't work very well with /proc/ so we're back to using ls and taking it // from there. - List processes = new(); + List processes = []; // List all processes by doing ls /proc/. // All subfolders which are completely numeric are PIDs @@ -237,7 +237,7 @@ public static IEnumerable ListProcesses(this IAdbClient client, /system/bin/ls -1 /proc/ fi".Replace("\r\n", "\n"), receiver); - Collection pids = new(); + Collection pids = []; string output = receiver.ToString(); using (StringReader reader = new(output)) diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index f110464c..75e06237 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -42,7 +42,7 @@ public virtual async Task InstallPackageAsync(string packageFilePath, bool reins ValidateDevice(); string remoteFilePath = await SyncPackageToDeviceAsync(packageFilePath, OnSyncProgressChanged, cancellationToken); - + await InstallRemotePackageAsync(remoteFilePath, reinstall, cancellationToken); InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(0, 1, PackageInstallProgressState.PostInstall)); @@ -113,7 +113,7 @@ void OnSplitSyncProgressChanged(object sender, SyncProgressChangedEventArgs args double present = 0; foreach (KeyValuePair info in progress) { - present += (info.Value / splitPackageFilePaths.Count) / 2; + present += info.Value / splitPackageFilePaths.Count / 2; } InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(count, splitPackageFilePaths.Count + 1, present)); @@ -174,7 +174,7 @@ void OnSyncProgressChanged(object sender, SyncProgressChangedEventArgs args) double present = 0; foreach (KeyValuePair info in progress) { - present += (info.Value / splitPackageFilePaths.Count) / 2; + present += info.Value / splitPackageFilePaths.Count / 2; } InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(count, splitPackageFilePaths.Count, present)); @@ -372,7 +372,7 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa #if NETCOREAPP3_0_OR_GREATER await #endif - using Stream stream = File.OpenRead(localFilePath); + using Stream stream = File.OpenRead(localFilePath); #if HAS_LOGGER logger.LogDebug($"Uploading file onto device '{Device.Serial}'"); #endif diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index 9f56ba00..d4879581 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -78,7 +78,7 @@ public PackageManager(IAdbClient client, DeviceData device, bool thirdPartyOnly ) { Device = device ?? throw new ArgumentNullException(nameof(device)); - Packages = new Dictionary(); + Packages = []; ThirdPartyOnly = thirdPartyOnly; this.client = client ?? throw new ArgumentNullException(nameof(client)); @@ -208,9 +208,9 @@ void OnSplitSyncProgressChanged(object sender, SyncProgressChangedEventArgs args } double present = 0; - foreach(KeyValuePair info in progress) + foreach (KeyValuePair info in progress) { - present += (info.Value / splitPackageFilePaths.Count) / 2; + present += info.Value / splitPackageFilePaths.Count / 2; } InstallProgressChanged?.Invoke(this, new InstallProgressEventArgs(count, splitPackageFilePaths.Count + 1, present)); diff --git a/AdvancedSharpAdbClient/DeviceMonitor.cs b/AdvancedSharpAdbClient/DeviceMonitor.cs index f7ae7ac3..cc03c2a5 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.cs @@ -81,7 +81,7 @@ public DeviceMonitor(IAdbSocket socket ) { Socket = socket ?? throw new ArgumentNullException(nameof(socket)); - devices = new List(); + devices = []; Devices = devices.AsReadOnly(); #if HAS_LOGGER this.logger = logger ?? NullLogger.Instance; diff --git a/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs b/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs index 8c9490eb..0fe5feb1 100644 --- a/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs +++ b/AdvancedSharpAdbClient/Extensions/SyncCommandConverter.cs @@ -17,7 +17,7 @@ public static class SyncCommandConverter /// /// Maps the values to their string representations. /// - private static readonly Dictionary Values = new() + private static readonly Dictionary Values = new(9) { { SyncCommand.DATA, "DATA" }, { SyncCommand.DENT, "DENT" }, diff --git a/AdvancedSharpAdbClient/Extensions/Utilities.cs b/AdvancedSharpAdbClient/Extensions/Utilities.cs index 959dedec..951d7438 100644 --- a/AdvancedSharpAdbClient/Extensions/Utilities.cs +++ b/AdvancedSharpAdbClient/Extensions/Utilities.cs @@ -84,6 +84,21 @@ public static bool IsNullOrWhiteSpace(this string value) #endif } +#if !UAP10_0_15138_0 && !NETCOREAPP2_1_OR_GREATER && !NETSTANDARD2_1_OR_GREATER + /// + /// Returns a value indicating whether a specified string occurs within this string, using the specified comparison rules. + /// + /// A sequence in which to locate a value. + /// The string to seek. + /// One of the enumeration values that specifies the rules to use in the comparison. + /// if the parameter occurs within this string, + /// or if is the empty string (""); otherwise, . + public static bool Contains(this string text, string value, StringComparison comparisonType) + { + return text.IndexOf(value, comparisonType) != -1; + } +#endif + /// /// Concatenates the members of a constructed collection of type , /// using the specified separator between each member. diff --git a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs index 9cf930ab..748fcbaf 100644 --- a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs @@ -51,6 +51,6 @@ public override string ToString() => /// The value to convert. /// A that represents in the system log. private static char FormatPriority(Priority value) => - PriorityFormatters?.TryGetValue(value, out var result) == true ? result : '?'; + PriorityFormatters?.TryGetValue(value, out char result) == true ? result : '?'; } } diff --git a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs index 20ee8884..1c2947c9 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs @@ -153,7 +153,7 @@ or LogId.Radio #if NETCOREAPP3_0_OR_GREATER await #endif - using (MemoryStream dataStream = new(data)) + using (MemoryStream dataStream = new(data)) { using BinaryReader reader = new(dataStream); int priority = reader.ReadInt32(); diff --git a/AdvancedSharpAdbClient/Logs/LogReader.cs b/AdvancedSharpAdbClient/Logs/LogReader.cs index dec055bd..e637a025 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.cs @@ -213,7 +213,7 @@ protected void ReadLogEntry(BinaryReader reader, Collection parent) case EventLogType.List: byte listLength = reader.ReadByte(); - Collection list = new(); + Collection list = []; for (int i = 0; i < listLength; i++) { diff --git a/AdvancedSharpAdbClient/Models/ForwardData.cs b/AdvancedSharpAdbClient/Models/ForwardData.cs index 96b1d4f4..50f57f2c 100644 --- a/AdvancedSharpAdbClient/Models/ForwardData.cs +++ b/AdvancedSharpAdbClient/Models/ForwardData.cs @@ -48,7 +48,7 @@ public ForwardData() /// The that represents the local (PC) endpoint. /// The that represents the remote (device) endpoint. public ForwardData(string serialNumber, string local, string remote) - { + { SerialNumber = serialNumber; Local = local; Remote = remote; diff --git a/AdvancedSharpAdbClient/SyncService.Async.cs b/AdvancedSharpAdbClient/SyncService.Async.cs index d7fc5d85..9c092210 100644 --- a/AdvancedSharpAdbClient/SyncService.Async.cs +++ b/AdvancedSharpAdbClient/SyncService.Async.cs @@ -240,7 +240,7 @@ public virtual async Task StatAsync(string remotePath, Cancellat /// public virtual async Task> GetDirectoryListingAsync(string remotePath, CancellationToken cancellationToken = default) { - Collection value = new(); + Collection value = []; // create the stat request message. await Socket.SendSyncRequestAsync(SyncCommand.LIST, remotePath, cancellationToken); diff --git a/Directory.Build.props b/Directory.Build.props index d6573528..d02fd8da 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -44,11 +44,20 @@ True + + 10.0 + + + + $(DefineConstants);UAP10_0_15138_0 + 10.0.15138.0 + + False en-US - $(DefineConstants);NETCORE;NETCORE_5_0;NETFX_CORE;WINDOWS_UWP + $(DefineConstants);NETCORE;NETCORE_5_0;NETFX_CORE;WINDOWS_UWP;UAP10_0 $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets UAP,Version=v10.0 .NETCore From 4f75be47a5e0e375aa8517912dbc3413b94db6fd Mon Sep 17 00:00:00 2001 From: wherewhere Date: Fri, 22 Sep 2023 21:37:59 +0800 Subject: [PATCH 3/9] Update constructors --- .../Models/AdbServerStatusTests.cs | 8 +- AdvancedSharpAdbClient/AdbClient.Async.cs | 6 +- AdvancedSharpAdbClient/AdbClient.cs | 6 +- AdvancedSharpAdbClient/AdbServer.Async.cs | 7 +- AdvancedSharpAdbClient/AdbServer.cs | 19 +- .../AdvancedSharpAdbClient.csproj | 2 +- .../DeviceCommands/LinuxPath.cs | 15 +- .../DeviceCommands/Models/AndroidProcess.cs | 557 +++++++++--------- .../Models/InstallProgressEventArgs.cs | 9 +- .../DeviceCommands/Models/VersionInfo.cs | 19 +- .../DeviceCommands/PackageManager.Async.cs | 4 +- .../DeviceCommands/PackageManager.cs | 4 +- .../Receivers/GetPropReceiver.cs | 5 + .../Receivers/InfoOutputReceiver.cs | 5 + .../Receivers/InstallOutputReceiver.cs | 5 + .../Receivers/PackageManagerReceiver.cs | 19 +- .../Receivers/ProcessOutputReceiver.cs | 7 +- AdvancedSharpAdbClient/DeviceMonitor.cs | 30 +- .../Exceptions/AdbException.cs | 3 +- .../Extensions/Utilities.cs | 24 +- .../Logs/AndroidLogEntry.cs | 7 +- AdvancedSharpAdbClient/Logs/EventLogEntry.cs | 5 + AdvancedSharpAdbClient/Logs/LogEntry.cs | 5 + AdvancedSharpAdbClient/Logs/LogReader.cs | 14 +- AdvancedSharpAdbClient/Logs/ShellStream.cs | 18 +- AdvancedSharpAdbClient/Models/AdbResponse.cs | 2 +- .../Models/AdbServerStatus.cs | 19 +- AdvancedSharpAdbClient/Models/DeviceData.cs | 52 +- .../Models/DeviceDataEventArgs.cs | 56 +- .../Models/FileStatistics.cs | 5 + AdvancedSharpAdbClient/Models/ForwardData.cs | 64 +- AdvancedSharpAdbClient/Models/ForwardSpec.cs | 76 +-- AdvancedSharpAdbClient/Models/Framebuffer.cs | 4 +- .../Models/FramebufferHeader.cs | 118 ++-- .../Models/SyncProgressChangedEventArgs.cs | 20 +- .../Receivers/ConsoleOutputReceiver.cs | 4 +- 36 files changed, 617 insertions(+), 606 deletions(-) diff --git a/AdvancedSharpAdbClient.Tests/Models/AdbServerStatusTests.cs b/AdvancedSharpAdbClient.Tests/Models/AdbServerStatusTests.cs index c6bca265..2c95bcf1 100644 --- a/AdvancedSharpAdbClient.Tests/Models/AdbServerStatusTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/AdbServerStatusTests.cs @@ -11,10 +11,10 @@ public class AdbServerStatusTests [Fact] public void ToStringTest() { - AdbServerStatus s = new(true, new Version(1, 0, 32)); - Assert.Equal("Version 1.0.32 of the adb daemon is running.", s.ToString()); - s.IsRunning = false; - Assert.Equal("The adb daemon is not running.", s.ToString()); + AdbServerStatus status = new(true, new Version(1, 0, 32)); + Assert.Equal("Version 1.0.32 of the adb daemon is running.", status.ToString()); + status.IsRunning = false; + Assert.Equal("The adb daemon is not running.", status.ToString()); } } } diff --git a/AdvancedSharpAdbClient/AdbClient.Async.cs b/AdvancedSharpAdbClient/AdbClient.Async.cs index 5ac7d873..7c0b8ca5 100644 --- a/AdvancedSharpAdbClient/AdbClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbClient.Async.cs @@ -53,7 +53,7 @@ public async Task> GetDevicesAsync(CancellationToken can string[] data = reply.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return data.Select(DeviceData.CreateFromAdbData); + return data.Select((x) => new DeviceData(x)); } /// @@ -151,7 +151,7 @@ public async Task> ListForwardAsync(DeviceData device, string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return parts.Select(ForwardData.FromString); + return parts.Select((x) => new ForwardData(x)); } /// @@ -169,7 +169,7 @@ public async Task> ListReverseForwardAsync(DeviceData d string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return parts.Select(ForwardData.FromString); + return parts.Select((x) => new ForwardData(x)); } /// diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index b7d5bb53..05fdbe16 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -197,7 +197,7 @@ public IEnumerable GetDevices() string[] data = reply.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return data.Select(DeviceData.CreateFromAdbData); + return data.Select((x) => new DeviceData(x)); } /// @@ -295,7 +295,7 @@ public IEnumerable ListForward(DeviceData device) string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return parts.Select(ForwardData.FromString); + return parts.Select((x) => new ForwardData(x)); } /// @@ -313,7 +313,7 @@ public IEnumerable ListReverseForward(DeviceData device) string[] parts = data.Split(separator, StringSplitOptions.RemoveEmptyEntries); - return parts.Select(ForwardData.FromString); + return parts.Select((x) => new ForwardData(x)); } /// diff --git a/AdvancedSharpAdbClient/AdbServer.Async.cs b/AdvancedSharpAdbClient/AdbServer.Async.cs index 3dc11978..d5a43af5 100644 --- a/AdvancedSharpAdbClient/AdbServer.Async.cs +++ b/AdvancedSharpAdbClient/AdbServer.Async.cs @@ -22,7 +22,7 @@ public virtual async Task StartServerAsync(string adbPath, bo if (commandLineClient.IsValidAdbFile(adbPath)) { - cachedAdbPath = adbPath; + CachedAdbPath = adbPath; commandLineVersion = await commandLineClient.GetVersionAsync(cancellationToken); } @@ -43,9 +43,6 @@ public virtual async Task StartServerAsync(string adbPath, bo ExceptionExtensions.ThrowIfNull(adbPath); await adbClient.KillAdbAsync(cancellationToken); - serverStatus.IsRunning = false; - serverStatus.Version = null; - await commandLineClient.StartServerAsync(cancellationToken); return StartServerResult.RestartedOutdatedDaemon; } @@ -68,7 +65,7 @@ public virtual async Task StartServerAsync(string adbPath, bo /// public virtual async Task RestartServerAsync(string adbPath, CancellationToken cancellationToken = default) { - adbPath ??= cachedAdbPath; + adbPath ??= CachedAdbPath; if (!IsValidAdbFile(adbPath)) { diff --git a/AdvancedSharpAdbClient/AdbServer.cs b/AdvancedSharpAdbClient/AdbServer.cs index db03ae1d..a6bc7d77 100644 --- a/AdvancedSharpAdbClient/AdbServer.cs +++ b/AdvancedSharpAdbClient/AdbServer.cs @@ -53,12 +53,6 @@ public partial class AdbServer(IAdbClient adbClient, Func protected static readonly object RestartLock = new(); - /// - /// The path to the adb server. Cached from calls to . Used when restarting - /// the server to figure out where adb is located. - /// - protected static string cachedAdbPath; - /// /// The current ADB client that manages the connection. /// @@ -94,6 +88,12 @@ public AdbServer(Func adbCommandLineClientFactory { } + /// + /// The path to the adb server. Cached from calls to . Used when restarting + /// the server to figure out where adb is located. + /// + protected static string CachedAdbPath { get; set; } + /// /// Gets or sets the default instance of the interface. /// @@ -109,7 +109,7 @@ public virtual StartServerResult StartServer(string adbPath, bool restartServerI if (commandLineClient.IsValidAdbFile(adbPath)) { - cachedAdbPath = adbPath; + CachedAdbPath = adbPath; commandLineVersion = commandLineClient.GetVersion(); } @@ -130,9 +130,6 @@ public virtual StartServerResult StartServer(string adbPath, bool restartServerI ExceptionExtensions.ThrowIfNull(adbPath); adbClient.KillAdb(); - serverStatus.IsRunning = false; - serverStatus.Version = null; - commandLineClient.StartServer(); return StartServerResult.RestartedOutdatedDaemon; } @@ -152,7 +149,7 @@ public virtual StartServerResult StartServer(string adbPath, bool restartServerI /// public virtual StartServerResult RestartServer(string adbPath = null) { - adbPath ??= cachedAdbPath; + adbPath ??= CachedAdbPath; if (!IsValidAdbFile(adbPath)) { diff --git a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj index 162538f8..98083f69 100644 --- a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj +++ b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj @@ -12,7 +12,7 @@ $(NoWarn);NU1603;NU1605 - net6.0;netstandard1.3;netstandard2.0;netstandard2.1 + net6.0;net8.0;netstandard1.3;netstandard2.0;netstandard2.1 $(TargetFrameworks);net8.0;netcoreapp2.1;netcoreapp3.1 $(TargetFrameworks);net2.0-client;net3.5-client;net4.0-client;net4.5.2;net4.6.2;net4.7.2;net4.8.1;net6.0-windows10.0.17763.0;net8.0-windows10.0.17763.0;netcore50;uap10.0;uap10.0.15138.0 diff --git a/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs b/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs index 9f3cf83a..ea7239b3 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/LinuxPath.cs @@ -26,10 +26,7 @@ public static partial class LinuxPath /// private const string EscapePattern = "([\\\\()*+?\"'#/\\s])"; - private static readonly char[] InvalidCharacters = new char[] - { - '|', '\\', '?', '*', '<', '\"', ':', '>' - }; + private static readonly char[] InvalidCharacters = ['|', '\\', '?', '*', '<', '\"', ':', '>']; /// /// Combine the specified paths to form one path. @@ -126,7 +123,7 @@ public static string GetDirectoryName(string path) #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER if (tpath.EndsWith(DirectorySeparatorChar)) #else - if (tpath.EndsWith(new string(new char[] { DirectorySeparatorChar }))) + if (tpath.EndsWith(new string([DirectorySeparatorChar]))) #endif { return tpath; @@ -140,7 +137,7 @@ public static string GetDirectoryName(string path) } else if (tpath.Length == 1) { - return new string(new char[] { DirectorySeparatorChar }); + return new string([DirectorySeparatorChar]); } } @@ -240,7 +237,7 @@ private static string FixupPath(string path) #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER if (sb != "." && !sb.StartsWith(DirectorySeparatorChar)) #else - if (sb != "." && !sb.StartsWith(new string(new char[] { DirectorySeparatorChar }))) + if (sb != "." && !sb.StartsWith(new string([DirectorySeparatorChar]))) #endif { sb = $".{DirectorySeparatorChar}{sb}"; @@ -249,13 +246,13 @@ private static string FixupPath(string path) #if NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER if (!sb.EndsWith(DirectorySeparatorChar)) #else - if (!sb.EndsWith(new string(new char[] { DirectorySeparatorChar }))) + if (!sb.EndsWith(new string([DirectorySeparatorChar]))) #endif { sb = $"{sb}{DirectorySeparatorChar}"; } - sb = sb.Replace("//", new string(new char[] { DirectorySeparatorChar })); + sb = sb.Replace("//", new string([DirectorySeparatorChar])); return sb; } diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs index c7dcc21d..7d9e4bfc 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/AndroidProcess.cs @@ -12,6 +12,288 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// public class AndroidProcess { + /// + /// Initializes a new instance of the class. + /// + public AndroidProcess() { } + + /// + /// Initializes a new instance of the class from it representation. + /// + /// A which represents a . + /// A value indicating whether the output of /proc/{pid}/stat is prefixed with /proc/{pid}/cmdline or not. + /// Because stat does not contain the full process name, this can be useful. + public AndroidProcess(string line, bool cmdLinePrefix = false) + { + ExceptionExtensions.ThrowIfNull(line); + + // See http://man7.org/linux/man-pages/man5/proc.5.html, + // section /proc/[pid]/stat, for more information about the file format + + // Space delimited, so normally we would just do a string.split + // The process name may contain spaces but is wrapped within parentheses, all other values (we know of) are + // numeric. + // So we parse the pid & process name manually, to account for this, and do the string.split afterwards :-) + int processNameStart = line.IndexOf('('); + int processNameEnd = line.LastIndexOf(')'); + + int pid; + string comm; + + bool parsedCmdLinePrefix = false; + + if (cmdLinePrefix) + { +#if HAS_INDEXRANGE + string[] cmdLineParts = line[..processNameStart] +#else + + string[] cmdLineParts = line.Substring(0, processNameStart) +#endif + .Split('\0'); + + if (cmdLineParts.Length <= 1) + { + parsedCmdLinePrefix = false; + } + else + { +#if HAS_INDEXRANGE + pid = int.Parse(cmdLineParts[^1]); +#else + pid = int.Parse(cmdLineParts[cmdLineParts.Length - 1]); +#endif + ProcessId = pid; + + comm = cmdLineParts[0]; + Name = comm; + + // All the other parts are the command line arguments, skip them. + parsedCmdLinePrefix = true; + } + } + + if (!parsedCmdLinePrefix) + { +#if HAS_INDEXRANGE + pid = int.Parse(line[..processNameStart]); +#else + pid = int.Parse(line.Substring(0, processNameStart)); +#endif + ProcessId = pid; + + comm = line.Substring(processNameStart + 1, processNameEnd - processNameStart - 1); + Name = comm; + } + +#if HAS_INDEXRANGE + string[] parts = line[(processNameEnd + 1)..] +#else + string[] parts = line.Substring(processNameEnd + 1) +#endif + .Split(' ', StringSplitOptions.RemoveEmptyEntries); + + if (parts.Length < 35) + { + throw new ArgumentOutOfRangeException(nameof(line)); + } + + // Only fields in Linux 2.1.10 and earlier are listed here, + // additional fields exist in newer versions of Linux. + string state = parts[0]; + State = (AndroidProcessState)Enum.Parse(typeof(AndroidProcessState), state, true); + + int ppid = ParseInt(parts[1]); + ParentProcessId = ppid; + + int pgrp = ParseInt(parts[2]); + ProcessGroupId = pgrp; + + int session = ParseInt(parts[3]); + SessionID = session; + + int tty_nr = ParseInt(parts[4]); + TTYNumber = tty_nr; + + int tpgid = ParseInt(parts[5]); + TopProcessGroupId = tpgid; + + uint flags = ParseUInt(parts[6]); + Flags = (PerProcessFlags)flags; + + ulong minflt = ParseULong(parts[7]); + MinorFaults = minflt; + + ulong cminflt = ParseULong(parts[8]); + ChildMinorFaults = cminflt; + + ulong majflt = ParseULong(parts[9]); + MajorFaults = majflt; + + ulong cmajflt = ParseULong(parts[10]); + ChildMajorFaults = cmajflt; + + ulong utime = ParseULong(parts[11]); + UserScheduledTime = utime; + + ulong stime = ParseULong(parts[12]); + ScheduledTime = stime; + + long cutime = ParseLong(parts[13]); + ChildUserScheduledTime = cutime; + + long cstime = ParseLong(parts[14]); + ChildScheduledTime = cstime; + + long priority = ParseLong(parts[15]); + Priority = priority; + + long nice = ParseLong(parts[16]); + Nice = nice; + + long num_threads = ParseLong(parts[17]); + ThreadsNumber = num_threads; + + long itrealvalue = ParseLong(parts[18]); + Interval = itrealvalue; + + ulong starttime = ParseULong(parts[19]); + StartTime = starttime; + + ulong vsize = ParseULong(parts[20]); + VirtualSize = vsize; + + int rss = int.Parse(parts[21]); + ResidentSetSize = rss; + + ulong rsslim = ParseULong(parts[22]); + ResidentSetSizeLimit = rsslim; + + ulong startcode = ParseULong(parts[23]); + StartCode = startcode; + + ulong endcode = ParseULong(parts[24]); + EndCode = endcode; + + ulong startstack = ParseULong(parts[25]); + StartStack = startstack; + + ulong kstkesp = ParseULong(parts[26]); + ESP = kstkesp; + + ulong kstkeip = ParseULong(parts[27]); + EIP = kstkeip; + + ulong signal = ParseULong(parts[28]); + Signal = signal; + + ulong blocked = ParseULong(parts[29]); + Blocked = blocked; + + ulong sigignore = ParseULong(parts[30]); + IgnoredSignals = sigignore; + + ulong sigcatch = ParseULong(parts[31]); + CaughtSignals = sigcatch; + + ulong wchan = ParseULong(parts[32]); + WChan = wchan; + + ulong nswap = ParseULong(parts[33]); + SwappedPagesNumber = nswap; + + ulong cnswap = ParseULong(parts[34]); + CumulativeSwappedPagesNumber = cnswap; + + if (parts.Length < 36) + { + return; + } + + // Linux 2.1.22 + int exit_signal = ParseInt(parts[35]); + ExitSignal = exit_signal; + + if (parts.Length < 37) + { + return; + } + + // Linux 2.2.8 + int processor = ParseInt(parts[36]); + Processor = processor; + + if (parts.Length < 39) + { + return; + } + + // Linux 2.5.19 + uint rt_priority = ParseUInt(parts[37]); + RealTimePriority = rt_priority; + + uint policy = ParseUInt(parts[38]); + Policy = policy; + + if (parts.Length < 40) + { + return; + } + + // Linux 2.6.18 + ulong delayacct_blkio_ticks = ParseULong(parts[39]); + + IODelays = delayacct_blkio_ticks; + + if (parts.Length < 42) + { + return; + } + + // Linux 2.6.24 + ulong guest_time = ParseULong(parts[40]); + GuestTime = guest_time; + + long cguest_time = ParseLong(parts[41]); + ChildGuestTime = cguest_time; + + if (parts.Length < 45) + { + return; + } + + // Linux 3.3 + ulong start_data = ParseULong(parts[42]); + StartData = start_data; + + ulong end_data = ParseULong(parts[43]); + EndData = end_data; + + ulong start_brk = ParseULong(parts[44]); + StartBrk = start_brk; + + if (parts.Length < 50) + { + return; + } + + // Linux 3.5 + ulong arg_start = ParseULong(parts[45]); + ArgStart = arg_start; + + ulong arg_end = ParseULong(parts[46]); + ArgEnd = arg_end; + + ulong env_start = ParseULong(parts[47]); + EnvStart = env_start; + + ulong env_end = ParseULong(parts[48]); + EnvEnd = env_end; + + int exit_code = ParseInt(parts[49]); + ExitCode = exit_code; + } + /// /// Gets or sets the state of the process. /// @@ -320,280 +602,7 @@ public class AndroidProcess /// A value indicating whether the output of /proc/{pid}/stat is prefixed with /proc/{pid}/cmdline or not. /// Because stat does not contain the full process name, this can be useful. /// The equivalent . - public static AndroidProcess Parse(string line, bool cmdLinePrefix = false) - { - ExceptionExtensions.ThrowIfNull(line); - - AndroidProcess process = new(); - - // See http://man7.org/linux/man-pages/man5/proc.5.html, - // section /proc/[pid]/stat, for more information about the file format - - // Space delimited, so normally we would just do a string.split - // The process name may contain spaces but is wrapped within parentheses, all other values (we know of) are - // numeric. - // So we parse the pid & process name manually, to account for this, and do the string.split afterwards :-) - int processNameStart = line.IndexOf('('); - int processNameEnd = line.LastIndexOf(')'); - - int pid; - string comm; - - bool parsedCmdLinePrefix = false; - - if (cmdLinePrefix) - { -#if HAS_INDEXRANGE - string[] cmdLineParts = line[..processNameStart] -#else - - string[] cmdLineParts = line.Substring(0, processNameStart) -#endif - .Split(new char[] { '\0' }); - - if (cmdLineParts.Length <= 1) - { - parsedCmdLinePrefix = false; - } - else - { -#if HAS_INDEXRANGE - pid = int.Parse(cmdLineParts[^1]); -#else - pid = int.Parse(cmdLineParts[cmdLineParts.Length - 1]); -#endif - process.ProcessId = pid; - - comm = cmdLineParts[0]; - process.Name = comm; - - // All the other parts are the command line arguments, skip them. - parsedCmdLinePrefix = true; - } - } - - if (!parsedCmdLinePrefix) - { -#if HAS_INDEXRANGE - pid = int.Parse(line[..processNameStart]); -#else - pid = int.Parse(line.Substring(0, processNameStart)); -#endif - process.ProcessId = pid; - - comm = line.Substring(processNameStart + 1, processNameEnd - processNameStart - 1); - process.Name = comm; - } - -#if HAS_INDEXRANGE - string[] parts = line[(processNameEnd + 1)..] -#else - string[] parts = line.Substring(processNameEnd + 1) -#endif - .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - - if (parts.Length < 35) - { - throw new ArgumentOutOfRangeException(nameof(line)); - } - - // Only fields in Linux 2.1.10 and earlier are listed here, - // additional fields exist in newer versions of Linux. - string state = parts[0]; - process.State = (AndroidProcessState)Enum.Parse(typeof(AndroidProcessState), state, true); - - int ppid = ParseInt(parts[1]); - process.ParentProcessId = ppid; - - int pgrp = ParseInt(parts[2]); - process.ProcessGroupId = pgrp; - - int session = ParseInt(parts[3]); - process.SessionID = session; - - int tty_nr = ParseInt(parts[4]); - process.TTYNumber = tty_nr; - - int tpgid = ParseInt(parts[5]); - process.TopProcessGroupId = tpgid; - - uint flags = ParseUInt(parts[6]); - process.Flags = (PerProcessFlags)flags; - - ulong minflt = ParseULong(parts[7]); - process.MinorFaults = minflt; - - ulong cminflt = ParseULong(parts[8]); - process.ChildMinorFaults = cminflt; - - ulong majflt = ParseULong(parts[9]); - process.MajorFaults = majflt; - - ulong cmajflt = ParseULong(parts[10]); - process.ChildMajorFaults = cmajflt; - - ulong utime = ParseULong(parts[11]); - process.UserScheduledTime = utime; - - ulong stime = ParseULong(parts[12]); - process.ScheduledTime = stime; - - long cutime = ParseLong(parts[13]); - process.ChildUserScheduledTime = cutime; - - long cstime = ParseLong(parts[14]); - process.ChildScheduledTime = cstime; - - long priority = ParseLong(parts[15]); - process.Priority = priority; - - long nice = ParseLong(parts[16]); - process.Nice = nice; - - long num_threads = ParseLong(parts[17]); - process.ThreadsNumber = num_threads; - - long itrealvalue = ParseLong(parts[18]); - process.Interval = itrealvalue; - - ulong starttime = ParseULong(parts[19]); - process.StartTime = starttime; - - ulong vsize = ParseULong(parts[20]); - process.VirtualSize = vsize; - - int rss = int.Parse(parts[21]); - process.ResidentSetSize = rss; - - ulong rsslim = ParseULong(parts[22]); - process.ResidentSetSizeLimit = rsslim; - - ulong startcode = ParseULong(parts[23]); - process.StartCode = startcode; - - ulong endcode = ParseULong(parts[24]); - process.EndCode = endcode; - - ulong startstack = ParseULong(parts[25]); - process.StartStack = startstack; - - ulong kstkesp = ParseULong(parts[26]); - process.ESP = kstkesp; - - ulong kstkeip = ParseULong(parts[27]); - process.EIP = kstkeip; - - ulong signal = ParseULong(parts[28]); - process.Signal = signal; - - ulong blocked = ParseULong(parts[29]); - process.Blocked = blocked; - - ulong sigignore = ParseULong(parts[30]); - process.IgnoredSignals = sigignore; - - ulong sigcatch = ParseULong(parts[31]); - process.CaughtSignals = sigcatch; - - ulong wchan = ParseULong(parts[32]); - process.WChan = wchan; - - ulong nswap = ParseULong(parts[33]); - process.SwappedPagesNumber = nswap; - - ulong cnswap = ParseULong(parts[34]); - process.CumulativeSwappedPagesNumber = cnswap; - - if (parts.Length < 36) - { - return process; - } - - // Linux 2.1.22 - int exit_signal = ParseInt(parts[35]); - process.ExitSignal = exit_signal; - - if (parts.Length < 37) - { - return process; - } - - // Linux 2.2.8 - int processor = ParseInt(parts[36]); - process.Processor = processor; - - if (parts.Length < 39) - { - return process; - } - - // Linux 2.5.19 - uint rt_priority = ParseUInt(parts[37]); - process.RealTimePriority = rt_priority; - - uint policy = ParseUInt(parts[38]); - process.Policy = policy; - - if (parts.Length < 40) - { - return process; - } - - // Linux 2.6.18 - ulong delayacct_blkio_ticks = ParseULong(parts[39]); - - process.IODelays = delayacct_blkio_ticks; - - if (parts.Length < 42) - { - return process; - } - - // Linux 2.6.24 - ulong guest_time = ParseULong(parts[40]); - process.GuestTime = guest_time; - - long cguest_time = ParseLong(parts[41]); - process.ChildGuestTime = cguest_time; - - if (parts.Length < 45) - { - return process; - } - - // Linux 3.3 - ulong start_data = ParseULong(parts[42]); - process.StartData = start_data; - - ulong end_data = ParseULong(parts[43]); - process.EndData = end_data; - - ulong start_brk = ParseULong(parts[44]); - process.StartBrk = start_brk; - - if (parts.Length < 50) - { - return process; - } - - // Linux 3.5 - ulong arg_start = ParseULong(parts[45]); - process.ArgStart = arg_start; - - ulong arg_end = ParseULong(parts[46]); - process.ArgEnd = arg_end; - - ulong env_start = ParseULong(parts[47]); - process.EnvStart = env_start; - - ulong env_end = ParseULong(parts[48]); - process.EnvEnd = env_end; - - int exit_code = ParseInt(parts[49]); - process.ExitCode = exit_code; - - return process; - } + public static AndroidProcess Parse(string line, bool cmdLinePrefix = false) => new(line, cmdLinePrefix); /// /// Gets a that represents this , diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/InstallProgressEventArgs.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/InstallProgressEventArgs.cs index c23d17aa..7d39b6b1 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/InstallProgressEventArgs.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/InstallProgressEventArgs.cs @@ -9,12 +9,12 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// /// Represents the state of the installation for . /// - public class InstallProgressEventArgs : EventArgs + public class InstallProgressEventArgs(PackageInstallProgressState state) : EventArgs { /// /// State of the installation. /// - public PackageInstallProgressState State { get; } + public PackageInstallProgressState State { get; } = state; /// /// Number of packages which is finished operation. @@ -38,11 +38,6 @@ public class InstallProgressEventArgs : EventArgs /// public double UploadProgress { get; } - /// - /// Initializes a new instance of the class. - /// - public InstallProgressEventArgs(PackageInstallProgressState state) => State = state; - /// /// Initializes a new instance of the class. /// Which is used for state. diff --git a/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs b/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs index c64b051a..600fd8fa 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Models/VersionInfo.cs @@ -7,28 +7,19 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// /// Represents a version of an Android application. /// - public class VersionInfo + /// The version code of the application. + /// The version name of the application. + public class VersionInfo(int versionCode, string versionName) { /// /// Gets or sets the version code of an Android application. /// - public int VersionCode { get; } + public int VersionCode { get; } = versionCode; /// /// Gets or sets the version name of an Android application. /// - public string VersionName { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The version code of the application. - /// The version name of the application. - public VersionInfo(int versionCode, string versionName) - { - VersionCode = versionCode; - VersionName = versionName; - } + public string VersionName { get; } = versionName; /// /// Deconstruct the class. diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index 75e06237..8daf99c9 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -449,8 +449,8 @@ protected virtual async Task CreateInstallSessionAsync(bool reinstall, s } string result = receiver.SuccessMessage; - int arr = result.IndexOf("]") - 1 - result.IndexOf("["); - string session = result.Substring(result.IndexOf("[") + 1, arr); + int arr = result.IndexOf(']') - 1 - result.IndexOf('['); + string session = result.Substring(result.IndexOf('[') + 1, arr); return session; } diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index d4879581..ff57eef4 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -527,8 +527,8 @@ protected virtual string CreateInstallSession(bool reinstall, string packageName } string result = receiver.SuccessMessage; - int arr = result.IndexOf("]") - 1 - result.IndexOf("["); - string session = result.Substring(result.IndexOf("[") + 1, arr); + int arr = result.IndexOf(']') - 1 - result.IndexOf('['); + string session = result.Substring(result.IndexOf('[') + 1, arr); return session; } diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs index 89435e1b..6d38e8f6 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/GetPropReceiver.cs @@ -22,6 +22,11 @@ public sealed partial class GetPropReceiver : MultiLineReceiver /// private const string GetPropPattern = "^\\[([^]]+)\\]\\:\\s*\\[(.*)\\]$"; + /// + /// Initializes a new instance of the class. + /// + public GetPropReceiver() { } + /// /// Gets the list of properties which have been retrieved. /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs index f7c0e213..f1631bdc 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InfoOutputReceiver.cs @@ -12,6 +12,11 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// public class InfoOutputReceiver : MultiLineReceiver { + /// + /// Initializes a new instance of the class. + /// + public InfoOutputReceiver() { } + /// /// Gets or sets a dictionary with the extracted properties and their corresponding values. /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs index 8e6a8a68..04c81832 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/InstallOutputReceiver.cs @@ -42,6 +42,11 @@ public partial class InstallOutputReceiver : MultiLineReceiver /// private const string ErrorPattern = @"Error:\s+(.*)?"; + /// + /// Initializes a new instance of the class. + /// + public InstallOutputReceiver() { } + /// /// Gets the error message if the install was unsuccessful. /// diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs index 9cc921dc..2a7c8a75 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/PackageManagerReceiver.cs @@ -9,28 +9,19 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// /// Parses the output of the various pm commands. /// - public class PackageManagerReceiver : MultiLineReceiver + /// The device for which the package information is being received. + /// The parent package manager. + public class PackageManagerReceiver(DeviceData device, PackageManager packageManager) : MultiLineReceiver { - /// - /// Initializes a new instance of the class. - /// - /// The device for which the package information is being received. - /// The parent package manager. - public PackageManagerReceiver(DeviceData device, PackageManager packageManager) - { - Device = device; - PackageManager = packageManager; - } - /// /// Gets the device. /// - public DeviceData Device { get; private set; } + public DeviceData Device { get; private set; } = device; /// /// Gets the package manager. /// - public PackageManager PackageManager { get; private set; } + public PackageManager PackageManager { get; private set; } = packageManager; /// /// Processes the new lines. diff --git a/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs b/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs index 136adb4a..aff2b399 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/Receivers/ProcessOutputReceiver.cs @@ -13,6 +13,11 @@ namespace AdvancedSharpAdbClient.DeviceCommands /// public class ProcessOutputReceiver : MultiLineReceiver { + /// + /// Initializes a new instance of the class. + /// + public ProcessOutputReceiver() { } + /// /// Gets a list of all processes that have been received. /// @@ -31,7 +36,7 @@ protected override void ProcessNewLines(IEnumerable lines) try { - Processes.Add(AndroidProcess.Parse(line, cmdLinePrefix: true)); + Processes.Add(new AndroidProcess(line, cmdLinePrefix: true)); } catch (Exception) { diff --git a/AdvancedSharpAdbClient/DeviceMonitor.cs b/AdvancedSharpAdbClient/DeviceMonitor.cs index cc03c2a5..f2f863fc 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.cs @@ -33,6 +33,8 @@ namespace AdvancedSharpAdbClient /// public partial class DeviceMonitor : IDeviceMonitor { + private static readonly string[] separator = ["\r\n", "\n"]; + private bool disposed = false; #if HAS_LOGGER @@ -66,6 +68,18 @@ public partial class DeviceMonitor : IDeviceMonitor protected Thread monitorThread; #endif + /// + public event EventHandler DeviceChanged; + + /// + public event EventHandler DeviceNotified; + + /// + public event EventHandler DeviceConnected; + + /// + public event EventHandler DeviceDisconnected; + #if !HAS_LOGGER #pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 #endif @@ -91,18 +105,6 @@ public DeviceMonitor(IAdbSocket socket #pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 #endif - /// - public event EventHandler DeviceChanged; - - /// - public event EventHandler DeviceNotified; - - /// - public event EventHandler DeviceConnected; - - /// - public event EventHandler DeviceDisconnected; - /// public ReadOnlyCollection Devices { get; private set; } @@ -285,9 +287,9 @@ private void InitializeSocket() /// private void ProcessIncomingDeviceData(string result) { - string[] deviceValues = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); + string[] deviceValues = result.Split(separator, StringSplitOptions.RemoveEmptyEntries); - IEnumerable currentDevices = deviceValues.Select(DeviceData.CreateFromAdbData); + IEnumerable currentDevices = deviceValues.Select((x) => new DeviceData(x)); UpdateDevices(currentDevices); } diff --git a/AdvancedSharpAdbClient/Exceptions/AdbException.cs b/AdvancedSharpAdbClient/Exceptions/AdbException.cs index fd38c129..e67addee 100644 --- a/AdvancedSharpAdbClient/Exceptions/AdbException.cs +++ b/AdvancedSharpAdbClient/Exceptions/AdbException.cs @@ -84,6 +84,7 @@ public AdbException(string message, Exception innerException) : base(message, in /// that the connection was reset by the remote server. This happens when the adb server was killed. /// public bool ConnectionReset => - InnerException is SocketException socketException && socketException.SocketErrorCode == SocketError.ConnectionReset; + InnerException is SocketException socketException + && socketException.SocketErrorCode == SocketError.ConnectionReset; } } diff --git a/AdvancedSharpAdbClient/Extensions/Utilities.cs b/AdvancedSharpAdbClient/Extensions/Utilities.cs index 951d7438..2d8fd9e0 100644 --- a/AdvancedSharpAdbClient/Extensions/Utilities.cs +++ b/AdvancedSharpAdbClient/Extensions/Utilities.cs @@ -93,10 +93,26 @@ public static bool IsNullOrWhiteSpace(this string value) /// One of the enumeration values that specifies the rules to use in the comparison. /// if the parameter occurs within this string, /// or if is the empty string (""); otherwise, . - public static bool Contains(this string text, string value, StringComparison comparisonType) - { - return text.IndexOf(value, comparisonType) != -1; - } + public static bool Contains(this string text, string value, StringComparison comparisonType) => + text.IndexOf(value, comparisonType) != -1; + + /// + /// Splits a string into substrings based on a specified delimiting character and, optionally, options. + /// + /// The string to split. + /// A character that delimits the substrings in this string. + /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. + /// An array whose elements contain the substrings from this instance that are delimited by . + public static string[] Split(this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => + text.Split(new[] { separator }, options); + + /// + /// Determines whether this string instance starts with the specified character. + /// + /// A sequence in which to locate a value. + /// The character to compare. + /// if matches the beginning of this string; otherwise, . + public static bool StartsWith(this string text, char value) => text.StartsWith(new string([value])); #endif /// diff --git a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs index 748fcbaf..8a5dfcf7 100644 --- a/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/AndroidLogEntry.cs @@ -15,7 +15,7 @@ public class AndroidLogEntry : LogEntry /// /// Maps Android log priorities to chars used to represent them in the system log. /// - private static readonly Dictionary PriorityFormatters = new() + private static readonly Dictionary PriorityFormatters = new(6) { { Priority.Verbose, 'V' }, { Priority.Debug, 'D' }, @@ -25,6 +25,11 @@ public class AndroidLogEntry : LogEntry { Priority.Assert, 'A' } }; + /// + /// Initializes a new instance of the class. + /// + public AndroidLogEntry() { } + /// /// Gets or sets the priority of the log message. /// diff --git a/AdvancedSharpAdbClient/Logs/EventLogEntry.cs b/AdvancedSharpAdbClient/Logs/EventLogEntry.cs index 5e7d5c4c..61beb24c 100644 --- a/AdvancedSharpAdbClient/Logs/EventLogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/EventLogEntry.cs @@ -12,6 +12,11 @@ namespace AdvancedSharpAdbClient.Logs /// public class EventLogEntry : LogEntry { + /// + /// Initializes a new instance of the class. + /// + public EventLogEntry() { } + /// /// Gets or sets the 4 bytes integer key from "/system/etc/event-log-tags" file. /// diff --git a/AdvancedSharpAdbClient/Logs/LogEntry.cs b/AdvancedSharpAdbClient/Logs/LogEntry.cs index 7076368e..d4aa810c 100644 --- a/AdvancedSharpAdbClient/Logs/LogEntry.cs +++ b/AdvancedSharpAdbClient/Logs/LogEntry.cs @@ -14,6 +14,11 @@ namespace AdvancedSharpAdbClient.Logs /// public class LogEntry { + /// + /// Initializes a new instance of the class. + /// + public LogEntry() { } + /// /// Gets or sets the process ID of the code that generated the log message. /// diff --git a/AdvancedSharpAdbClient/Logs/LogReader.cs b/AdvancedSharpAdbClient/Logs/LogReader.cs index e637a025..256a44fa 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.cs @@ -13,18 +13,13 @@ namespace AdvancedSharpAdbClient.Logs /// /// Processes Android log files in binary format. You usually get the binary format by running logcat -B. /// - public partial class LogReader + /// A that contains the logcat data. + public partial class LogReader(Stream stream) { /// /// The that contains the logcat data. /// - private readonly Stream stream; - - /// - /// Initializes a new instance of the class. - /// - /// A that contains the logcat data. - public LogReader(Stream stream) => this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); + private readonly Stream stream = stream ?? throw new ArgumentNullException(nameof(stream)); /// /// Reads the next from the stream. @@ -59,7 +54,6 @@ public virtual LogEntry ReadEntry() // header size and payload length. // For both objects, the size should be 0x18 uint id = 0; - uint uid = 0; if (headerSize != 0) { @@ -84,7 +78,7 @@ public virtual LogEntry ReadEntry() return null; } - uid = uidValue.Value; + _ = uidValue.Value; } if (headerSize >= 0x20) diff --git a/AdvancedSharpAdbClient/Logs/ShellStream.cs b/AdvancedSharpAdbClient/Logs/ShellStream.cs index 740ba3f2..3b86044d 100644 --- a/AdvancedSharpAdbClient/Logs/ShellStream.cs +++ b/AdvancedSharpAdbClient/Logs/ShellStream.cs @@ -232,7 +232,7 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke #endif } - byte[] minibuffer = new byte[1]; + byte[] miniBuffer = new byte[1]; // Loop over the data, and find a LF (0x0d) character. If it is // followed by a CR (0x0a) character, remove the LF character and @@ -264,11 +264,11 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke int miniRead = #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - await Inner.ReadAsync(minibuffer.AsMemory(0, 1), cancellationToken).ConfigureAwait(false); + await Inner.ReadAsync(miniBuffer.AsMemory(0, 1), cancellationToken).ConfigureAwait(false); #elif !NET35 - await Inner.ReadAsync(minibuffer, 0, 1, cancellationToken).ConfigureAwait(false); + await Inner.ReadAsync(miniBuffer, 0, 1, cancellationToken).ConfigureAwait(false); #else - Inner.Read(minibuffer, 0, 1); + Inner.Read(miniBuffer, 0, 1); #endif if (miniRead == 0) @@ -280,7 +280,7 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke else { // Append the byte to the buffer. - buffer[offset + read - 1] = minibuffer[0]; + buffer[offset + read - 1] = miniBuffer[0]; } } } @@ -291,13 +291,13 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke { int miniRead = #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - await Inner.ReadAsync(minibuffer.AsMemory(0, 1), cancellationToken).ConfigureAwait(false); + await Inner.ReadAsync(miniBuffer.AsMemory(0, 1), cancellationToken).ConfigureAwait(false); #elif !NET35 - await Inner.ReadAsync(minibuffer, 0, 1, cancellationToken).ConfigureAwait(false); + await Inner.ReadAsync(miniBuffer, 0, 1, cancellationToken).ConfigureAwait(false); #else - Inner.Read(minibuffer, 0, 1); + Inner.Read(miniBuffer, 0, 1); #endif - int nextByte = minibuffer[0]; + int nextByte = miniBuffer[0]; if (nextByte == 0x0a) { diff --git a/AdvancedSharpAdbClient/Models/AdbResponse.cs b/AdvancedSharpAdbClient/Models/AdbResponse.cs index 5a89ddb0..1bfea2b8 100644 --- a/AdvancedSharpAdbClient/Models/AdbResponse.cs +++ b/AdvancedSharpAdbClient/Models/AdbResponse.cs @@ -19,7 +19,7 @@ public class AdbResponse /// /// Gets a that represents the OK response sent by ADB. /// - public static AdbResponse OK { get; } = new AdbResponse() + public static AdbResponse OK { get; } = new() { IOSuccess = true, Okay = true, diff --git a/AdvancedSharpAdbClient/Models/AdbServerStatus.cs b/AdvancedSharpAdbClient/Models/AdbServerStatus.cs index 1caa6bf7..49982160 100644 --- a/AdvancedSharpAdbClient/Models/AdbServerStatus.cs +++ b/AdvancedSharpAdbClient/Models/AdbServerStatus.cs @@ -9,28 +9,19 @@ namespace AdvancedSharpAdbClient /// /// Represents the status of the adb server. /// - public struct AdbServerStatus + /// The value indicating whether the server is currently running. + /// The version of the server when it is running. + public struct AdbServerStatus(bool isRunning, Version version) { /// /// Gets a value indicating whether the server is currently running. /// - public bool IsRunning { get; internal set; } + public bool IsRunning { get; set; } = isRunning; /// /// Gets the version of the server when it is running. /// - public Version Version { get; internal set; } - - /// - /// Initializes a new instance of the struct. - /// - /// The value indicating whether the server is currently running. - /// The version of the server when it is running. - public AdbServerStatus(bool isRunning, Version version) - { - IsRunning = isRunning; - Version = version; - } + public Version Version { get; set; } = version; /// /// Deconstruct the struct. diff --git a/AdvancedSharpAdbClient/Models/DeviceData.cs b/AdvancedSharpAdbClient/Models/DeviceData.cs index 08c1d54b..659c7ca1 100644 --- a/AdvancedSharpAdbClient/Models/DeviceData.cs +++ b/AdvancedSharpAdbClient/Models/DeviceData.cs @@ -15,13 +15,44 @@ public partial class DeviceData /// /// A regular expression that can be used to parse the device information that is returned by the Android Debut Bridge. /// - internal const string DeviceDataRegexString = @"^(?[a-zA-Z0-9_-]+(?:\s?[\.a-zA-Z0-9_-]+)?(?:\:\d{1,})?)\s+(?device|connecting|offline|unknown|bootloader|recovery|download|authorizing|unauthorized|host|no permissions)(?.*?)(\s+usb:(?[^:]+))?(?:\s+product:(?[^:]+))?(\s+model\:(?[\S]+))?(\s+device\:(?[\S]+))?(\s+features:(?[^:]+))?(\s+transport_id:(?[^:]+))?$"; + private const string DeviceDataRegexString = @"^(?[a-zA-Z0-9_-]+(?:\s?[\.a-zA-Z0-9_-]+)?(?:\:\d{1,})?)\s+(?device|connecting|offline|unknown|bootloader|recovery|download|authorizing|unauthorized|host|no permissions)(?.*?)(\s+usb:(?[^:]+))?(?:\s+product:(?[^:]+))?(\s+model\:(?[\S]+))?(\s+device\:(?[\S]+))?(\s+features:(?[^:]+))?(\s+transport_id:(?[^:]+))?$"; /// /// A regular expression that can be used to parse the device information that is returned by the Android Debut Bridge. /// private static readonly Regex Regex = DeviceDataRegex(); + /// + /// Initializes a new instance of the class. + /// + public DeviceData() { } + + /// + /// Initializes a new instance of the class based on + /// data retrieved from the Android Debug Bridge. + /// + /// The data retrieved from the Android Debug Bridge that represents a device. + public DeviceData(string data) + { + Match match = Regex.Match(data); + if (!match.Success) + { + throw new ArgumentException($"Invalid device list data '{data}'"); + } + else + { + Serial = match.Groups["serial"].Value; + State = GetStateFromString(match.Groups["state"].Value); + Model = match.Groups["model"].Value; + Product = match.Groups["product"].Value; + Name = match.Groups["device"].Value; + Features = match.Groups["features"].Value; + Usb = match.Groups["usb"].Value; + TransportId = match.Groups["transport_id"].Value; + Message = match.Groups["message"].Value; + } + } + /// /// Gets or sets the device serial number. /// @@ -73,24 +104,7 @@ public partial class DeviceData /// /// The data retrieved from the Android Debug Bridge that represents a device. /// A object that represents the device. - public static DeviceData CreateFromAdbData(string data) - { - Match m = Regex.Match(data); - return m.Success - ? new DeviceData() - { - Serial = m.Groups["serial"].Value, - State = GetStateFromString(m.Groups["state"].Value), - Model = m.Groups["model"].Value, - Product = m.Groups["product"].Value, - Name = m.Groups["device"].Value, - Features = m.Groups["features"].Value, - Usb = m.Groups["usb"].Value, - TransportId = m.Groups["transport_id"].Value, - Message = m.Groups["message"].Value - } - : throw new ArgumentException($"Invalid device list data '{data}'"); - } + public static DeviceData CreateFromAdbData(string data) => new(data); /// public override string ToString() => Serial; diff --git a/AdvancedSharpAdbClient/Models/DeviceDataEventArgs.cs b/AdvancedSharpAdbClient/Models/DeviceDataEventArgs.cs index d4d74ab9..7ca8681f 100644 --- a/AdvancedSharpAdbClient/Models/DeviceDataEventArgs.cs +++ b/AdvancedSharpAdbClient/Models/DeviceDataEventArgs.cs @@ -10,82 +10,58 @@ namespace AdvancedSharpAdbClient /// /// The event arguments that are passed when a device event occurs. /// - public class DeviceDataEventArgs : EventArgs + /// The device. + public class DeviceDataEventArgs(DeviceData device) : EventArgs { - /// - /// Initializes a new instance of the class. - /// - /// The device. - public DeviceDataEventArgs(DeviceData device) => Device = device; - /// /// Gets the device where the change occurred. /// /// The device where the change occurred. - public DeviceData Device { get; } + public DeviceData Device { get; } = device; } /// /// The event arguments that are passed when a device event occurs. /// - public class DeviceDataNotifyEventArgs : EventArgs + /// The list of device. + public class DeviceDataNotifyEventArgs(IEnumerable devices) : EventArgs { - /// - /// Initializes a new instance of the class. - /// - /// The list of device. - public DeviceDataNotifyEventArgs(IEnumerable devices) => Devices = devices; - /// /// Gets the list of device where the change occurred. /// /// The list of device where the change occurred. - public IEnumerable Devices { get; } + public IEnumerable Devices { get; } = devices; } /// /// The event arguments that are passed when a device event occurs. /// - public class DeviceDataConnectEventArgs : DeviceDataEventArgs + /// The device. + /// The device after the reported change. + public class DeviceDataConnectEventArgs(DeviceData device, bool isConnect) : DeviceDataEventArgs(device) { - /// - /// Initializes a new instance of the class. - /// - /// The device. - /// The device after the reported change. - public DeviceDataConnectEventArgs(DeviceData device, bool isConnect) : base(device) => IsConnect = isConnect; - /// /// Gets the connect state of the device after the reported change. /// - public bool IsConnect { get; } + public bool IsConnect { get; } = isConnect; } /// /// The event arguments that are passed when a device event occurs. /// - public class DeviceDataChangeEventArgs : DeviceDataEventArgs + /// The device. + /// The state of the device after the reported change. + /// The state of the device before the reported change. + public class DeviceDataChangeEventArgs(DeviceData device, DeviceState newState, DeviceState oldState) : DeviceDataEventArgs(device) { - /// - /// Initializes a new instance of the class. - /// - /// The device. - /// The state of the device after the reported change. - /// The state of the device before the reported change. - public DeviceDataChangeEventArgs(DeviceData device, DeviceState newState, DeviceState oldState) : base(device) - { - NewState = newState; - OldState = oldState; - } - /// /// Gets the state of the device after the reported change. /// - public DeviceState NewState { get; } + public DeviceState NewState { get; } = newState; /// /// Gets the state of the device before the reported change. /// - public DeviceState OldState { get; } + public DeviceState OldState { get; } = oldState; } } diff --git a/AdvancedSharpAdbClient/Models/FileStatistics.cs b/AdvancedSharpAdbClient/Models/FileStatistics.cs index 6f6af668..186d65e9 100644 --- a/AdvancedSharpAdbClient/Models/FileStatistics.cs +++ b/AdvancedSharpAdbClient/Models/FileStatistics.cs @@ -11,6 +11,11 @@ namespace AdvancedSharpAdbClient /// public class FileStatistics { + /// + /// Initializes a new instance of the class. + /// + public FileStatistics() { } + /// /// Gets or sets the path of the file. /// diff --git a/AdvancedSharpAdbClient/Models/ForwardData.cs b/AdvancedSharpAdbClient/Models/ForwardData.cs index 50f57f2c..782e070b 100644 --- a/AdvancedSharpAdbClient/Models/ForwardData.cs +++ b/AdvancedSharpAdbClient/Models/ForwardData.cs @@ -9,6 +9,36 @@ namespace AdvancedSharpAdbClient /// public class ForwardData { + /// + /// Initializes a new instance of the class. + /// + public ForwardData() { } + + /// + /// Initializes a new instance of the class. + /// + /// The serial number of the device for which the port forwarding is configured. + /// The that represents the local (PC) endpoint. + /// The that represents the remote (device) endpoint. + public ForwardData(string serialNumber, string local, string remote) + { + SerialNumber = serialNumber; + Local = local; + Remote = remote; + } + + /// + /// Initializes a new instance of the class by parsing a . + /// + /// The value to parse. + public ForwardData(string value) + { + string[] parts = value.Split(' '); + SerialNumber = parts[0]; + Local = parts[1]; + Remote = parts[2]; + } + /// /// Gets or sets the serial number of the device for which the port forwarding is configured. /// @@ -22,7 +52,7 @@ public class ForwardData /// /// Gets a that represents the local (PC) endpoint. /// - public ForwardSpec LocalSpec => ForwardSpec.Parse(Local); + public ForwardSpec LocalSpec => new(Local); /// /// Gets or sets a that represents the remote (device) endpoint. @@ -32,42 +62,14 @@ public class ForwardData /// /// Gets a that represents the remote (device) endpoint. /// - public ForwardSpec RemoteSpec => ForwardSpec.Parse(Remote); - - /// - /// Initializes a new instance of the struct. - /// - public ForwardData() - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The serial number of the device for which the port forwarding is configured. - /// The that represents the local (PC) endpoint. - /// The that represents the remote (device) endpoint. - public ForwardData(string serialNumber, string local, string remote) - { - SerialNumber = serialNumber; - Local = local; - Remote = remote; - } + public ForwardSpec RemoteSpec => new(Remote); /// /// Creates a new instance of the class by parsing a . /// /// The value to parse. /// A object that represents the port forwarding information contained in . - public static ForwardData FromString(string value) - { - if (value == null) - { - return null; - } - string[] parts = value.Split(' '); - return new ForwardData(parts[0], parts[1], parts[2]); - } + public static ForwardData FromString(string value) => value == null ? null : new ForwardData(value); /// public override string ToString() => $"{SerialNumber} {Local} {Remote}"; diff --git a/AdvancedSharpAdbClient/Models/ForwardSpec.cs b/AdvancedSharpAdbClient/Models/ForwardSpec.cs index 305a69a6..03a7c568 100644 --- a/AdvancedSharpAdbClient/Models/ForwardSpec.cs +++ b/AdvancedSharpAdbClient/Models/ForwardSpec.cs @@ -19,7 +19,7 @@ public class ForwardSpec /// value, used for the representation of the /// class. /// - private static readonly Dictionary Mappings = new(StringComparer.OrdinalIgnoreCase) + private static readonly Dictionary Mappings = new(6, StringComparer.OrdinalIgnoreCase) { { "tcp", ForwardProtocol.Tcp }, { "localabstract", ForwardProtocol.LocalAbstract }, @@ -30,35 +30,15 @@ public class ForwardSpec }; /// - /// Gets or sets the protocol which is being forwarded. + /// Initializes a new instance of the class. /// - public ForwardProtocol Protocol { get; set; } + public ForwardSpec() { } /// - /// Gets or sets, when the is , the port - /// number of the port being forwarded. - /// - public int Port { get; set; } - - /// - /// Gets or sets, when the is , - /// or , - /// the Unix domain socket name of the socket being forwarded. - /// - public string SocketName { get; set; } - - /// - /// Gets or sets, when the is , - /// the process id of the process to which the debugger is attached. - /// - public int ProcessId { get; set; } - - /// - /// Creates a from its representation. + /// Initializes a new instance of the class from its representation. /// /// A which represents a . - /// A which represents . - public static ForwardSpec Parse(string spec) + public ForwardSpec(string spec) { ExceptionExtensions.ThrowIfNull(spec); @@ -75,12 +55,7 @@ public static ForwardSpec Parse(string spec) } ForwardProtocol protocol = Mappings[parts[0]]; - - ForwardSpec value = new() - { - Protocol = protocol - }; - + Protocol = protocol; bool isInt = int.TryParse(parts[1], out int intValue); @@ -92,7 +67,7 @@ public static ForwardSpec Parse(string spec) throw new ArgumentOutOfRangeException(nameof(spec)); } - value.ProcessId = intValue; + ProcessId = intValue; break; case ForwardProtocol.Tcp: @@ -101,20 +76,49 @@ public static ForwardSpec Parse(string spec) throw new ArgumentOutOfRangeException(nameof(spec)); } - value.Port = intValue; + Port = intValue; break; case ForwardProtocol.LocalAbstract or ForwardProtocol.LocalFilesystem or ForwardProtocol.LocalReserved or ForwardProtocol.Device: - value.SocketName = parts[1]; + SocketName = parts[1]; break; } - - return value; } + /// + /// Gets or sets the protocol which is being forwarded. + /// + public ForwardProtocol Protocol { get; set; } + + /// + /// Gets or sets, when the is , the port + /// number of the port being forwarded. + /// + public int Port { get; set; } + + /// + /// Gets or sets, when the is , + /// or , + /// the Unix domain socket name of the socket being forwarded. + /// + public string SocketName { get; set; } + + /// + /// Gets or sets, when the is , + /// the process id of the process to which the debugger is attached. + /// + public int ProcessId { get; set; } + + /// + /// Creates a from its representation. + /// + /// A which represents a . + /// A which represents . + public static ForwardSpec Parse(string spec) => new(spec); + /// public override string ToString() { diff --git a/AdvancedSharpAdbClient/Models/Framebuffer.cs b/AdvancedSharpAdbClient/Models/Framebuffer.cs index 6093e46a..8657afb1 100644 --- a/AdvancedSharpAdbClient/Models/Framebuffer.cs +++ b/AdvancedSharpAdbClient/Models/Framebuffer.cs @@ -100,7 +100,7 @@ public virtual void Refresh(bool reset = false) if (reset || !headerInitialized) { - Header = FramebufferHeader.Read(headerData); + Header = new FramebufferHeader(headerData); headerInitialized = true; } @@ -148,7 +148,7 @@ public virtual async Task RefreshAsync(bool reset = false, CancellationToken can if (reset || !headerInitialized) { - Header = FramebufferHeader.Read(headerData); + Header = new FramebufferHeader(headerData); headerInitialized = true; } diff --git a/AdvancedSharpAdbClient/Models/FramebufferHeader.cs b/AdvancedSharpAdbClient/Models/FramebufferHeader.cs index dabb4cbc..fc081f4e 100644 --- a/AdvancedSharpAdbClient/Models/FramebufferHeader.cs +++ b/AdvancedSharpAdbClient/Models/FramebufferHeader.cs @@ -18,6 +18,65 @@ namespace AdvancedSharpAdbClient /// public struct FramebufferHeader { + /// + /// Initializes a new instance of the struct based on a byte array which contains the data. + /// + /// The data that feeds the struct. + /// As defined in + public FramebufferHeader(byte[] data) + { + // Read the data from a MemoryStream so we can use the BinaryReader to process the data. + using MemoryStream stream = new(data); + using BinaryReader reader = new(stream, Encoding.ASCII +#if !NETFRAMEWORK || NET45_OR_GREATER + , leaveOpen: true +#endif + ); + Version = reader.ReadUInt32(); + + if (Version > 2) + { + // Technically, 0 is not a supported version either; we assume version 0 indicates + // an empty framebuffer. + throw new InvalidOperationException($"Framebuffer version {Version} is not supported"); + } + + Bpp = reader.ReadUInt32(); + + if (Version >= 2) + { + ColorSpace = reader.ReadUInt32(); + } + + Size = reader.ReadUInt32(); + Width = reader.ReadUInt32(); + Height = reader.ReadUInt32(); + + Red = new ColorData + { + Offset = reader.ReadUInt32(), + Length = reader.ReadUInt32() + }; + + Blue = new ColorData + { + Offset = reader.ReadUInt32(), + Length = reader.ReadUInt32() + }; + + Green = new ColorData + { + Offset = reader.ReadUInt32(), + Length = reader.ReadUInt32() + }; + + Alpha = new ColorData + { + Offset = reader.ReadUInt32(), + Length = reader.ReadUInt32() + }; + } + /// /// Gets or sets the version of the framebuffer struct. /// @@ -73,64 +132,7 @@ public struct FramebufferHeader /// /// The data that feeds the struct. /// A new object. - public static FramebufferHeader Read(byte[] data) - { - // as defined in https://android.googlesource.com/platform/system/core/+/master/adb/framebuffer_service.cpp - FramebufferHeader header = default; - - // Read the data from a MemoryStream so we can use the BinaryReader to process the data. - using MemoryStream stream = new(data); - using BinaryReader reader = new(stream, Encoding.ASCII -#if !NETFRAMEWORK || NET45_OR_GREATER - , leaveOpen: true -#endif - ); - header.Version = reader.ReadUInt32(); - - if (header.Version > 2) - { - // Technically, 0 is not a supported version either; we assume version 0 indicates - // an empty framebuffer. - throw new InvalidOperationException($"Framebuffer version {header.Version} is not supported"); - } - - header.Bpp = reader.ReadUInt32(); - - if (header.Version >= 2) - { - header.ColorSpace = reader.ReadUInt32(); - } - - header.Size = reader.ReadUInt32(); - header.Width = reader.ReadUInt32(); - header.Height = reader.ReadUInt32(); - - header.Red = new ColorData - { - Offset = reader.ReadUInt32(), - Length = reader.ReadUInt32() - }; - - header.Blue = new ColorData - { - Offset = reader.ReadUInt32(), - Length = reader.ReadUInt32() - }; - - header.Green = new ColorData - { - Offset = reader.ReadUInt32(), - Length = reader.ReadUInt32() - }; - - header.Alpha = new ColorData - { - Offset = reader.ReadUInt32(), - Length = reader.ReadUInt32() - }; - - return header; - } + public static FramebufferHeader Read(byte[] data) => new(data); #if HAS_DRAWING /// diff --git a/AdvancedSharpAdbClient/Models/SyncProgressChangedEventArgs.cs b/AdvancedSharpAdbClient/Models/SyncProgressChangedEventArgs.cs index 38cc3e7c..d054258b 100644 --- a/AdvancedSharpAdbClient/Models/SyncProgressChangedEventArgs.cs +++ b/AdvancedSharpAdbClient/Models/SyncProgressChangedEventArgs.cs @@ -9,29 +9,23 @@ namespace AdvancedSharpAdbClient /// /// Provides data for the event. /// - public class SyncProgressChangedEventArgs : EventArgs + public class SyncProgressChangedEventArgs(long received, long total) : EventArgs { - /// - /// Gets the number of progress percentage for the sync operation. - /// - public double ProgressPercentage => TotalBytesToReceive != 0L ? ReceivedBytesSize * 100.0 / TotalBytesToReceive : 0.0; - /// /// Gets the number of bytes sync to the local computer. /// /// An representing the number of sync bytes. - public long ReceivedBytesSize { get; } + public long ReceivedBytesSize { get; } = received; /// /// Gets the total number of bytes for the sync operation. /// /// An representing the total size of the download, in bytes. - public long TotalBytesToReceive { get; } + public long TotalBytesToReceive { get; } = total; - internal SyncProgressChangedEventArgs(long received, long total) - { - ReceivedBytesSize = received; - TotalBytesToReceive = total; - } + /// + /// Gets the number of progress percentage for the sync operation. + /// + public double ProgressPercentage => TotalBytesToReceive != 0L ? ReceivedBytesSize * 100.0 / TotalBytesToReceive : 0.0; } } diff --git a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs index 5ad3702f..69265c31 100644 --- a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs @@ -132,13 +132,11 @@ protected override void ProcessNewLines(IEnumerable lines) { foreach (string line in lines) { - if (string.IsNullOrEmpty(line) || line.StartsWith("#") || line.StartsWith("$")) + if (string.IsNullOrEmpty(line) || line.StartsWith('#') || line.StartsWith('$')) { continue; } - output.AppendLine(line); - #if HAS_LOGGER logger.LogDebug(line); #endif From f039ff62b233489fb73bf8447e7dfa6ba48cbdf1 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Fri, 22 Sep 2023 22:11:22 +0800 Subject: [PATCH 4/9] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 50 +++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bfd7d215..38113b28 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,13 +1,20 @@ name: build and test -on: [push, pull_request] +on: + push: + branches: + - main + - 'version/**' + pull_request: + branches: + - main + workflow_dispatch: env: DOTNET_VERSION: '8.0.x' # The .NET SDK version to use jobs: build-and-test: - name: build-and-test-${{matrix.os}} runs-on: ${{matrix.os}} strategy: @@ -15,7 +22,11 @@ jobs: os: [windows-latest, ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup .NET Core App uses: actions/setup-dotnet@v3 with: @@ -24,9 +35,38 @@ jobs: - name: Install dependencies run: dotnet restore -p:FullTargets=false - + - name: Build run: dotnet build --no-restore -p:FullTargets=false - + - name: Test run: dotnet test --no-restore -p:FullTargets=false + + pack-and-upload: + name: pack-and-upload + needs: build-and-test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup .NET Core App + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{env.DOTNET_VERSION}} + dotnet-quality: 'preview' + + - name: Install dependencies + run: dotnet restore -p:FullTargets=false + + - name: Pack + run: dotnet pack --no-restore -o "nugets" -p:FullTargets=false + + - name: Upload + uses: actions/upload-artifact@v3 + with: + name: Nuget Package + path: nugets/** From 564a6e2aba7de6e0c4f12b4b7ac19be9784444bc Mon Sep 17 00:00:00 2001 From: wherewhere Date: Tue, 26 Sep 2023 18:12:00 +0800 Subject: [PATCH 5/9] Update array initialize --- .../PackageManagerTests.Async.cs | 12 ++++----- .../DeviceCommands/PackageManagerTests.cs | 12 ++++----- .../DeviceMonitorTests.cs | 2 +- .../Extensions/SyncCommandConverterTests.cs | 4 +-- .../Models/FramebufferHeaderTests.cs | 2 +- .../SyncServiceTests.Async.cs | 25 ++++++++----------- .../SyncServiceTests.cs | 11 ++++---- .../Exceptions/JavaException.cs | 4 ++- .../Extensions/CrossPlatformFunc.cs | 10 +++++--- .../Extensions/Utilities.cs | 14 +++++++++++ AdvancedSharpAdbClient/Models/ForwardSpec.cs | 2 +- 11 files changed, 55 insertions(+), 43 deletions(-) diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs index 381b856a..9aa6744a 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.Async.cs @@ -85,7 +85,7 @@ public async void InstallMultipleRemotePackageAsyncTest() }; PackageManager manager = new(adbClient, device); - await manager.InstallMultipleRemotePackageAsync("/data/base.apk", new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, false); + await manager.InstallMultipleRemotePackageAsync("/data/base.apk", ["/data/split-dpi.apk", "/data/split-abi.apk"], false); Assert.Equal(6, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create", adbClient.ReceivedCommands[1]); @@ -94,7 +94,7 @@ public async void InstallMultipleRemotePackageAsyncTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[4]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[5]); - await manager.InstallMultipleRemotePackageAsync("/data/base.apk", new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, true); + await manager.InstallMultipleRemotePackageAsync("/data/base.apk", ["/data/split-dpi.apk", "/data/split-abi.apk"], true); Assert.Equal(11, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -r", adbClient.ReceivedCommands[6]); @@ -103,7 +103,7 @@ public async void InstallMultipleRemotePackageAsyncTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[9]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[10]); - await manager.InstallMultipleRemotePackageAsync(new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, "com.google.android.gms", false); + await manager.InstallMultipleRemotePackageAsync(["/data/split-dpi.apk", "/data/split-abi.apk"], "com.google.android.gms", false); Assert.Equal(15, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -p com.google.android.gms", adbClient.ReceivedCommands[11]); @@ -111,7 +111,7 @@ public async void InstallMultipleRemotePackageAsyncTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[13]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[14]); - await manager.InstallMultipleRemotePackageAsync(new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, "com.google.android.gms", true); + await manager.InstallMultipleRemotePackageAsync(["/data/split-dpi.apk", "/data/split-abi.apk"], "com.google.android.gms", true); Assert.Equal(19, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -r -p com.google.android.gms", adbClient.ReceivedCommands[15]); @@ -148,7 +148,7 @@ public async void InstallMultiplePackageAsyncTest() }; PackageManager manager = new(adbClient, device); - await manager.InstallMultiplePackageAsync("Assets/test.txt", new string[] { "Assets/gapps.txt", "Assets/logcat.bin" }, false); + await manager.InstallMultiplePackageAsync("Assets/test.txt", ["Assets/gapps.txt", "Assets/logcat.bin"], false); Assert.Equal(9, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create", adbClient.ReceivedCommands[1]); Assert.Equal("pm install-write 936013062 base.apk \"/data/local/tmp/test.txt\"", adbClient.ReceivedCommands[2]); @@ -165,7 +165,7 @@ public async void InstallMultiplePackageAsyncTest() Assert.True(syncService.UploadedFiles.ContainsKey("/data/local/tmp/logcat.bin")); syncService.UploadedFiles.Clear(); - await manager.InstallMultiplePackageAsync(new string[] { "Assets/gapps.txt", "Assets/logcat.bin" }, "com.google.android.gms", false); + await manager.InstallMultiplePackageAsync(["Assets/gapps.txt", "Assets/logcat.bin"], "com.google.android.gms", false); Assert.Equal(15, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -p com.google.android.gms", adbClient.ReceivedCommands[9]); Assert.Equal("pm install-write 936013062 splitapp0.apk \"/data/local/tmp/gapps.txt\"", adbClient.ReceivedCommands[10]); diff --git a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs index 3710528d..bbefd19d 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceCommands/PackageManagerTests.cs @@ -114,7 +114,7 @@ public void InstallMultipleRemotePackageTest() }; PackageManager manager = new(adbClient, device); - manager.InstallMultipleRemotePackage("/data/base.apk", new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, false); + manager.InstallMultipleRemotePackage("/data/base.apk", ["/data/split-dpi.apk", "/data/split-abi.apk"], false); Assert.Equal(6, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create", adbClient.ReceivedCommands[1]); @@ -123,7 +123,7 @@ public void InstallMultipleRemotePackageTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[4]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[5]); - manager.InstallMultipleRemotePackage("/data/base.apk", new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, true); + manager.InstallMultipleRemotePackage("/data/base.apk", ["/data/split-dpi.apk", "/data/split-abi.apk"], true); Assert.Equal(11, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -r", adbClient.ReceivedCommands[6]); @@ -132,7 +132,7 @@ public void InstallMultipleRemotePackageTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[9]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[10]); - manager.InstallMultipleRemotePackage(new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, "com.google.android.gms", false); + manager.InstallMultipleRemotePackage(["/data/split-dpi.apk", "/data/split-abi.apk"], "com.google.android.gms", false); Assert.Equal(15, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -p com.google.android.gms", adbClient.ReceivedCommands[11]); @@ -140,7 +140,7 @@ public void InstallMultipleRemotePackageTest() Assert.Equal("pm install-write 936013062 splitapp1.apk \"/data/split-abi.apk\"", adbClient.ReceivedCommands[13]); Assert.Equal("pm install-commit 936013062", adbClient.ReceivedCommands[14]); - manager.InstallMultipleRemotePackage(new string[] { "/data/split-dpi.apk", "/data/split-abi.apk" }, "com.google.android.gms", true); + manager.InstallMultipleRemotePackage(["/data/split-dpi.apk", "/data/split-abi.apk"], "com.google.android.gms", true); Assert.Equal(19, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -r -p com.google.android.gms", adbClient.ReceivedCommands[15]); @@ -177,7 +177,7 @@ public void InstallMultiplePackageTest() }; PackageManager manager = new(adbClient, device); - manager.InstallMultiplePackage("Assets/test.txt", new string[] { "Assets/gapps.txt", "Assets/logcat.bin" }, false); + manager.InstallMultiplePackage("Assets/test.txt", ["Assets/gapps.txt", "Assets/logcat.bin"], false); Assert.Equal(9, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create", adbClient.ReceivedCommands[1]); Assert.Equal("pm install-write 936013062 base.apk \"/data/local/tmp/test.txt\"", adbClient.ReceivedCommands[2]); @@ -194,7 +194,7 @@ public void InstallMultiplePackageTest() Assert.True(syncService.UploadedFiles.ContainsKey("/data/local/tmp/logcat.bin")); syncService.UploadedFiles.Clear(); - manager.InstallMultiplePackage(new string[] { "Assets/gapps.txt", "Assets/logcat.bin" }, "com.google.android.gms", false); + manager.InstallMultiplePackage(["Assets/gapps.txt", "Assets/logcat.bin"], "com.google.android.gms", false); Assert.Equal(15, adbClient.ReceivedCommands.Count); Assert.Equal("pm install-create -p com.google.android.gms", adbClient.ReceivedCommands[9]); Assert.Equal("pm install-write 936013062 splitapp0.apk \"/data/local/tmp/gapps.txt\"", adbClient.ReceivedCommands[10]); diff --git a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs index 01c76b47..67576303 100644 --- a/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs +++ b/AdvancedSharpAdbClient.Tests/DeviceMonitorTests.cs @@ -280,7 +280,7 @@ public void AdbKilledTest() using DeviceMonitor monitor = new(Socket); RunTest( - new AdbResponse[] { AdbResponse.OK, AdbResponse.OK }, + [AdbResponse.OK, AdbResponse.OK], ResponseMessages( DummyAdbSocket.ServerDisconnected, string.Empty), diff --git a/AdvancedSharpAdbClient.Tests/Extensions/SyncCommandConverterTests.cs b/AdvancedSharpAdbClient.Tests/Extensions/SyncCommandConverterTests.cs index e0e65c15..1840e85d 100644 --- a/AdvancedSharpAdbClient.Tests/Extensions/SyncCommandConverterTests.cs +++ b/AdvancedSharpAdbClient.Tests/Extensions/SyncCommandConverterTests.cs @@ -14,11 +14,11 @@ public void GetCommandNullTest() => [Fact] public void GetCommandInvalidNumberOfBytesTest() => - _ = Assert.Throws(() => SyncCommandConverter.GetCommand(new byte[] { })); + _ = Assert.Throws(() => SyncCommandConverter.GetCommand([])); [Fact] public void GetCommandInvalidCommandTest() => - _ = Assert.Throws(() => SyncCommandConverter.GetCommand(new byte[] { (byte)'Q', (byte)'M', (byte)'T', (byte)'V' })); + _ = Assert.Throws(() => SyncCommandConverter.GetCommand("QMTV"u8.ToArray())); [Fact] public void GetBytesInvalidCommandTest() => diff --git a/AdvancedSharpAdbClient.Tests/Models/FramebufferHeaderTests.cs b/AdvancedSharpAdbClient.Tests/Models/FramebufferHeaderTests.cs index b407cedb..2992625a 100644 --- a/AdvancedSharpAdbClient.Tests/Models/FramebufferHeaderTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/FramebufferHeaderTests.cs @@ -91,7 +91,7 @@ public void ToImageEmptyTest() byte[] data = File.ReadAllBytes("Assets/framebufferheader-empty.bin"); FramebufferHeader header = FramebufferHeader.Read(data); - byte[] framebuffer = Array.Empty(); + byte[] framebuffer = []; Bitmap image = header.ToImage(framebuffer); Assert.Null(image); diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs index 1337dc61..29533b22 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.Async.cs @@ -25,8 +25,8 @@ await RunTestAsync( NoResponseMessages, Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello"), - new[] { SyncCommand.STAT }, - new byte[][] { [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0] }, + [SyncCommand.STAT], + [[160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0]], null, async () => { @@ -56,14 +56,13 @@ await RunTestAsync( ResponseMessages(".", "..", "sdcard0", "emulated"), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.LIST, "/storage"), - new[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, - new byte[][] - { + [SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE], + [ [233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], [237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], [255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86], [109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86] - }, + ], null, async () => { @@ -118,13 +117,12 @@ await RunTestAsync( ResponseMessages(), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello").Union(SyncRequests(SyncCommand.RECV, "/fstab.donatello")), - new SyncCommand[] { SyncCommand.STAT, SyncCommand.DATA, SyncCommand.DONE }, - new byte[][] - { + [SyncCommand.STAT, SyncCommand.DATA, SyncCommand.DONE], + [ [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0], contentLength, content - }, + ], null, async () => { @@ -161,12 +159,9 @@ await RunTestAsync( SyncRequests( SyncCommand.SEND, "/sdcard/test,644", SyncCommand.DONE, "1446505200"), - new[] { SyncCommand.OKAY }, + [SyncCommand.OKAY], null, - new byte[][] - { - [.. contentMessage] - }, + [[.. contentMessage]], async () => { using SyncService service = new(Socket, device); diff --git a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs index 56582c2f..b2d0c376 100644 --- a/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs +++ b/AdvancedSharpAdbClient.Tests/SyncServiceTests.cs @@ -36,8 +36,8 @@ public void StatTest() NoResponseMessages, Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.STAT, "/fstab.donatello"), - new[] { SyncCommand.STAT }, - new byte[][] { [160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0] }, + [SyncCommand.STAT], + [[160, 129, 0, 0, 85, 2, 0, 0, 0, 0, 0, 0]], null, () => { @@ -67,14 +67,13 @@ public void GetListingTest() ResponseMessages(".", "..", "sdcard0", "emulated"), Requests("host:transport:169.254.109.177:5555", "sync:"), SyncRequests(SyncCommand.LIST, "/storage"), - new[] { SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE }, - new byte[][] - { + [SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DENT, SyncCommand.DONE], + [ [233, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], [237, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86], [255, 161, 0, 0, 24, 0, 0, 0, 152, 130, 56, 86], [109, 65, 0, 0, 0, 0, 0, 0, 152, 130, 56, 86] - }, + ], null, () => { diff --git a/AdvancedSharpAdbClient/Exceptions/JavaException.cs b/AdvancedSharpAdbClient/Exceptions/JavaException.cs index aae34213..91ec24a8 100644 --- a/AdvancedSharpAdbClient/Exceptions/JavaException.cs +++ b/AdvancedSharpAdbClient/Exceptions/JavaException.cs @@ -15,6 +15,8 @@ public partial class JavaException : Exception private const string ExceptionOutput = "java.lang."; private const string ExceptionPattern = @"java.lang.(\w+Exception):\s+(.*)?"; + private static readonly char[] separator = ['\r', '\n']; + /// /// Gets the name of Java exception. /// @@ -80,7 +82,7 @@ public JavaException(string name, string message, string stackTrace, Exception i /// /// A which represents a . /// The equivalent . - public static JavaException Parse(string line) => Parse(line.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)); + public static JavaException Parse(string line) => Parse(line.Split(separator, StringSplitOptions.RemoveEmptyEntries)); /// diff --git a/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs b/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs index af5c80a6..e21642dd 100644 --- a/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs +++ b/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs @@ -15,6 +15,8 @@ namespace AdvancedSharpAdbClient /// public static class CrossPlatformFunc { + private static readonly char[] separator = ['\r', '\n']; + /// /// Determines whether the specified file exists. /// @@ -40,9 +42,9 @@ public static class CrossPlatformFunc string standardErrorString = process.StandardError.ReadToEnd(); string standardOutputString = process.StandardOutput.ReadToEnd(); - errorOutput?.AddRange(standardErrorString.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)); + errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - standardOutput?.AddRange(standardOutputString.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)); + standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); // get the return code from the process if (!process.WaitForExit(5000)) @@ -89,9 +91,9 @@ public static class CrossPlatformFunc string standardErrorString = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); string standardOutputString = await process.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - errorOutput?.AddRange(standardErrorString.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)); + errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - standardOutput?.AddRange(standardOutputString.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)); + standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); #if NET5_0_OR_GREATER using (CancellationTokenSource completionSource = new(TimeSpan.FromMilliseconds(5000))) diff --git a/AdvancedSharpAdbClient/Extensions/Utilities.cs b/AdvancedSharpAdbClient/Extensions/Utilities.cs index 2d8fd9e0..9c878119 100644 --- a/AdvancedSharpAdbClient/Extensions/Utilities.cs +++ b/AdvancedSharpAdbClient/Extensions/Utilities.cs @@ -106,6 +106,20 @@ public static bool Contains(this string text, string value, StringComparison com public static string[] Split(this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => text.Split(new[] { separator }, options); + /// + /// Splits a string into a maximum number of substrings based on a specified delimiting + /// character and, optionally, options. Splits a string into a maximum number of + /// substrings based on the provided character separator, optionally omitting empty + /// substrings from the result. + /// + /// The string to split. + /// A character that delimits the substrings in this string. + /// The maximum number of elements expected in the array. + /// A bitwise combination of the enumeration values that specifies whether to trim substrings and include empty substrings. + /// An array that contains at most count substrings from this instance that are delimited by . + public static string[] Split(this string text, char separator, int count, StringSplitOptions options = StringSplitOptions.None) => + text.Split(new[] { separator }, count, options); + /// /// Determines whether this string instance starts with the specified character. /// diff --git a/AdvancedSharpAdbClient/Models/ForwardSpec.cs b/AdvancedSharpAdbClient/Models/ForwardSpec.cs index 03a7c568..a1306adb 100644 --- a/AdvancedSharpAdbClient/Models/ForwardSpec.cs +++ b/AdvancedSharpAdbClient/Models/ForwardSpec.cs @@ -42,7 +42,7 @@ public ForwardSpec(string spec) { ExceptionExtensions.ThrowIfNull(spec); - string[] parts = spec.Split(new char[] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries); + string[] parts = spec.Split(':', 2, StringSplitOptions.RemoveEmptyEntries); if (parts.Length != 2) { From f81b8555e3de00c0ffe4b260505b4179d45677f5 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Wed, 27 Sep 2023 16:00:09 +0800 Subject: [PATCH 6/9] Move ShellStream out of logs folder --- .../{Logs => Models}/ShellStreamTests.cs | 2 +- AdvancedSharpAdbClient/{Logs => Models}/ShellStream.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) rename AdvancedSharpAdbClient.Tests/{Logs => Models}/ShellStreamTests.cs (99%) rename AdvancedSharpAdbClient/{Logs => Models}/ShellStream.cs (98%) diff --git a/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs b/AdvancedSharpAdbClient.Tests/Models/ShellStreamTests.cs similarity index 99% rename from AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs rename to AdvancedSharpAdbClient.Tests/Models/ShellStreamTests.cs index 13a2bff3..6556db21 100644 --- a/AdvancedSharpAdbClient.Tests/Logs/ShellStreamTests.cs +++ b/AdvancedSharpAdbClient.Tests/Models/ShellStreamTests.cs @@ -3,7 +3,7 @@ using System.Text; using Xunit; -namespace AdvancedSharpAdbClient.Logs.Tests +namespace AdvancedSharpAdbClient.Tests { public class ShellStreamTests { diff --git a/AdvancedSharpAdbClient/Logs/ShellStream.cs b/AdvancedSharpAdbClient/Models/ShellStream.cs similarity index 98% rename from AdvancedSharpAdbClient/Logs/ShellStream.cs rename to AdvancedSharpAdbClient/Models/ShellStream.cs index 3b86044d..664c837c 100644 --- a/AdvancedSharpAdbClient/Logs/ShellStream.cs +++ b/AdvancedSharpAdbClient/Models/ShellStream.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; using System.Threading; -namespace AdvancedSharpAdbClient.Logs +namespace AdvancedSharpAdbClient { /// Represents a that wraps around an inner that contains /// output from an Android shell command. In the shell output, the LF character is replaced by a @@ -114,8 +114,8 @@ public override int Read(byte[] buffer, int offset, int count) continue; } - byte[] minibuffer = new byte[1]; - int miniRead = Inner.Read(minibuffer, 0, 1); + byte[] miniBuffer = new byte[1]; + int miniRead = Inner.Read(miniBuffer, 0, 1); if (miniRead == 0) { @@ -126,7 +126,7 @@ public override int Read(byte[] buffer, int offset, int count) else { // Append the byte to the buffer. - buffer[offset + read - 1] = minibuffer[0]; + buffer[offset + read - 1] = miniBuffer[0]; } } } From 09d57c4585583b7bc74eaddaf047370cd531c029 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Wed, 27 Sep 2023 17:02:52 +0800 Subject: [PATCH 7/9] Replace Microsoft.Extensions.Logging with custom ILogger --- .../AdbCommandLineClient.Async.cs | 2 - .../AdbCommandLineClient.cs | 21 +-- AdvancedSharpAdbClient/AdbSocket.Async.cs | 16 -- AdvancedSharpAdbClient/AdbSocket.cs | 59 +------ .../AdvancedSharpAdbClient.csproj | 126 ++------------- .../DeviceCommands/PackageManager.Async.cs | 15 +- .../DeviceCommands/PackageManager.cs | 34 +--- AdvancedSharpAdbClient/DeviceMonitor.Async.cs | 17 -- AdvancedSharpAdbClient/DeviceMonitor.cs | 19 +-- .../Extensions/LoggerExtensions.cs | 149 +++++++++++------- AdvancedSharpAdbClient/Logs/Enums/LogLevel.cs | 52 ++++++ .../Logs/Interfaces/ILogger.cs | 35 ++++ .../Logs/Interfaces/ILoggerFactory.cs | 28 ++++ AdvancedSharpAdbClient/Logs/LoggerProvider.cs | 34 ++++ AdvancedSharpAdbClient/Logs/NullLogger.cs | 34 ++++ AdvancedSharpAdbClient/Logs/NullLoggerT.cs | 55 ------- .../Properties/GlobalUsings.cs | 5 - .../Receivers/ConsoleOutputReceiver.cs | 43 +---- 18 files changed, 309 insertions(+), 435 deletions(-) create mode 100644 AdvancedSharpAdbClient/Logs/Enums/LogLevel.cs create mode 100644 AdvancedSharpAdbClient/Logs/Interfaces/ILogger.cs create mode 100644 AdvancedSharpAdbClient/Logs/Interfaces/ILoggerFactory.cs create mode 100644 AdvancedSharpAdbClient/Logs/LoggerProvider.cs create mode 100644 AdvancedSharpAdbClient/Logs/NullLogger.cs delete mode 100644 AdvancedSharpAdbClient/Logs/NullLoggerT.cs diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs index 609b68c3..b6ed11cf 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs @@ -32,9 +32,7 @@ public virtual async Task GetVersionAsync(CancellationToken cancellatio if (version < AdbServer.RequiredAdbVersion) { AdbException ex = new($"Required minimum version of adb: {AdbServer.RequiredAdbVersion}. Current version is {version}"); -#if HAS_LOGGER logger.LogError(ex, ex.Message); -#endif throw ex; } diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.cs index 5a8b8ed7..4aea2e19 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.cs @@ -3,6 +3,7 @@ // using AdvancedSharpAdbClient.Exceptions; +using AdvancedSharpAdbClient.Logs; using System; using System.Collections.Generic; using System.ComponentModel; @@ -22,27 +23,18 @@ public partial class AdbCommandLineClient : IAdbCommandLineClient /// protected const string AdbVersionPattern = "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"; -#if HAS_LOGGER /// /// The logger to use when logging messages. /// protected readonly ILogger logger; -#endif -#if !HAS_LOGGER -#pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Initializes a new instance of the class. /// /// The path to the adb.exe executable. /// Don't check adb file name when . /// The logger to use when logging. - public AdbCommandLineClient(string adbPath, bool isForce = false -#if HAS_LOGGER - , ILogger logger = null -#endif - ) + public AdbCommandLineClient(string adbPath, bool isForce = false, ILogger logger = null) { if (adbPath.IsNullOrWhiteSpace()) { @@ -77,13 +69,8 @@ public AdbCommandLineClient(string adbPath, bool isForce = false this.EnsureIsValidAdbFile(adbPath); AdbPath = adbPath; -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } -#if !HAS_LOGGER -#pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Gets the path to the adb.exe executable. @@ -107,9 +94,7 @@ public virtual Version GetVersion() if (version < AdbServer.RequiredAdbVersion) { AdbException ex = new($"Required minimum version of adb: {AdbServer.RequiredAdbVersion}. Current version is {version}"); -#if HAS_LOGGER logger.LogError(ex, ex.Message); -#endif throw ex; } diff --git a/AdvancedSharpAdbClient/AdbSocket.Async.cs b/AdvancedSharpAdbClient/AdbSocket.Async.cs index 34559e0b..8cc83f7e 100644 --- a/AdvancedSharpAdbClient/AdbSocket.Async.cs +++ b/AdvancedSharpAdbClient/AdbSocket.Async.cs @@ -28,14 +28,9 @@ public virtual async Task SendAsync(byte[] data, int offset, int length, Cancell throw new AdbException("channel EOF"); } } -#if HAS_LOGGER catch (SocketException ex) { logger.LogError(ex, ex.Message); -#else - catch (SocketException) - { -#endif throw; } } @@ -115,16 +110,12 @@ public virtual async Task ReadAsync(byte[] data, int length, CancellationTo if (count < 0) { -#if HAS_LOGGER logger.LogError("read: channel EOF"); -#endif throw new AdbException("EOF"); } else if (count == 0) { -#if HAS_LOGGER logger.LogInformation("DONE with Read"); -#endif } else { @@ -244,14 +235,9 @@ protected virtual async Task WriteAsync(byte[] data, CancellationToken can { await SendAsync(data, -1, cancellationToken); } -#if HAS_LOGGER catch (IOException e) { logger.LogError(e, e.Message); -#else - catch (IOException) - { -#endif return false; } @@ -278,9 +264,7 @@ protected virtual async Task ReadAdbResponseInnerAsync(Cancellation { string message = await ReadStringAsync(cancellationToken); rasps.Message = message; -#if HAS_LOGGER logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{rasps.Message}'"); -#endif } return rasps; diff --git a/AdvancedSharpAdbClient/AdbSocket.cs b/AdvancedSharpAdbClient/AdbSocket.cs index ccb296bd..19e66e68 100644 --- a/AdvancedSharpAdbClient/AdbSocket.cs +++ b/AdvancedSharpAdbClient/AdbSocket.cs @@ -31,33 +31,22 @@ public partial class AdbSocket : IAdbSocket /// protected readonly ITcpSocket socket; -#if HAS_LOGGER /// /// The logger to use when logging messages. /// protected readonly ILogger logger; -#endif -#if !HAS_LOGGER -#pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Initializes a new instance of the class. /// /// The at which the Android Debug Bridge is listening for clients. /// The logger to use when logging. - public AdbSocket(EndPoint endPoint -#if HAS_LOGGER - , ILogger logger = null -#endif - ) + public AdbSocket(EndPoint endPoint, ILogger logger = null) { socket = new TcpSocket(); socket.Connect(endPoint); socket.ReceiveBufferSize = ReceiveBufferSize; -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } /// @@ -66,11 +55,7 @@ public AdbSocket(EndPoint endPoint /// The host address at which the Android Debug Bridge is listening for clients. /// The port at which the Android Debug Bridge is listening for clients. /// The logger to use when logging. - public AdbSocket(string host, int port -#if HAS_LOGGER - , ILogger logger = null -#endif - ) + public AdbSocket(string host, int port, ILogger logger = null) { if (string.IsNullOrEmpty(host)) { @@ -86,24 +71,18 @@ public AdbSocket(string host, int port socket = new TcpSocket(); socket.Connect(endPoint); socket.ReceiveBufferSize = ReceiveBufferSize; -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } -#if !HAS_LOGGER -#pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Initializes a new instance of the class. /// /// The at which the Android Debug Bridge is listening for clients. - public AdbSocket(ITcpSocket socket) + /// The logger to use when logging. + public AdbSocket(ITcpSocket socket, ILogger logger = null) { this.socket = socket; -#if HAS_LOGGER - logger ??= NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } /// @@ -143,14 +122,9 @@ public virtual void Send(byte[] data, int offset, int length) throw new AdbException("channel EOF"); } } -#if HAS_LOGGER catch (SocketException sex) { logger.LogError(sex, sex.Message); -#else - catch (SocketException) - { -#endif throw; } } @@ -222,16 +196,12 @@ public virtual int Read(byte[] data, int length) count = socket.Receive(buffer, bufferLength, SocketFlags.None); if (count < 0) { -#if HAS_LOGGER logger.LogError("read: channel EOF"); -#endif throw new AdbException("EOF"); } else if (count == 0) { -#if HAS_LOGGER logger.LogInformation("DONE with Read"); -#endif } else { @@ -364,14 +334,9 @@ protected virtual bool Write(byte[] data) { Send(data, -1); } -#if HAS_LOGGER catch (IOException e) { logger.LogError(e, e.Message); -#else - catch (IOException) - { -#endif return false; } @@ -397,9 +362,7 @@ protected virtual AdbResponse ReadAdbResponseInner() { string message = ReadString(); rasps.Message = message; -#if HAS_LOGGER - logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{rasps.Message}'"); -#endif + logger.LogError("Got reply '{0}', diag='{1}'", ReplyToString(reply), rasps.Message); } return rasps; @@ -417,17 +380,11 @@ protected virtual string ReplyToString(byte[] reply) { result = Encoding.ASCII.GetString(reply); } -#if HAS_LOGGER catch (DecoderFallbackException e) { logger.LogError(e, e.Message); -#else - catch (DecoderFallbackException) - { -#endif result = string.Empty; } - return result; } diff --git a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj index 98083f69..450e5d0c 100644 --- a/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj +++ b/AdvancedSharpAdbClient/AdvancedSharpAdbClient.csproj @@ -4,8 +4,6 @@ False True True - True - False $(NoWarn);CS1685;CA2254 @@ -55,145 +53,39 @@ - + - - - - - - - - - + - + $(DefineConstants);HAS_TASK - + $(DefineConstants);HAS_BUFFERS - - $(DefineConstants);HAS_LOGGER - - - + $(DefineConstants);HAS_DRAWING - + $(DefineConstants);HAS_DRAWING - + $(DefineConstants);HAS_INDEXRANGE - + $(DefineConstants);HAS_RUNTIMEINFORMATION - - $(DefineConstants);HAS_LOGGER;HAS_OLDLOGGER - - - + $(DefineConstants);HAS_PROCESS;HAS_SERIALIZATION diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index 8daf99c9..c5b58471 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -358,9 +358,7 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa // workitem: 19711 string remoteFilePath = LinuxPath.Combine(TempInstallationDirectory, packageFileName); -#if HAS_LOGGER logger.LogDebug(packageFileName, $"Uploading {packageFileName} onto device '{Device.Serial}'"); -#endif using (ISyncService sync = syncServiceFactory(client, Device)) { @@ -373,9 +371,8 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa await #endif using Stream stream = File.OpenRead(localFilePath); -#if HAS_LOGGER + logger.LogDebug($"Uploading file onto device '{Device.Serial}'"); -#endif // As C# can't use octal, the octal literal 666 (rw-Permission) is here converted to decimal (438) await sync.PushAsync(stream, remoteFilePath, 438, File.GetLastWriteTime(localFilePath), null, cancellationToken); @@ -383,14 +380,9 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa return remoteFilePath; } -#if HAS_LOGGER catch (IOException e) { logger.LogError(e, $"Unable to open sync connection! reason: {e.Message}"); -#else - catch (IOException) - { -#endif throw; } finally @@ -413,14 +405,9 @@ protected virtual async Task RemoveRemotePackageAsync(string remoteFilePath, Can { await client.ExecuteShellCommandAsync(Device, $"rm \"{remoteFilePath}\"", null, cancellationToken); } -#if HAS_LOGGER catch (IOException e) { logger.LogError(e, $"Failed to delete temporary package: {e.Message}"); -#else - catch (IOException) - { -#endif throw; } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index ff57eef4..8439f9ef 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -3,6 +3,7 @@ // using AdvancedSharpAdbClient.Exceptions; +using AdvancedSharpAdbClient.Logs; using System; using System.Collections.Generic; using System.Diagnostics; @@ -31,12 +32,10 @@ public partial class PackageManager /// protected const string ListThirdPartyOnly = "pm list packages -f -3"; -#if HAS_LOGGER /// /// The logger to use when logging messages. /// protected readonly ILogger logger; -#endif /// /// The to use when communicating with the device. @@ -55,9 +54,6 @@ public partial class PackageManager /// public event EventHandler InstallProgressChanged; -#if !HAS_LOGGER -#pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Initializes a new instance of the class. /// @@ -71,11 +67,7 @@ public partial class PackageManager /// A value indicating whether to skip the initial refresh of the package list or not. /// Used mainly by unit tests. /// The logger to use when logging. - public PackageManager(IAdbClient client, DeviceData device, bool thirdPartyOnly = false, Func syncServiceFactory = null, bool skipInit = false -#if HAS_LOGGER - , ILogger logger = null -#endif - ) + public PackageManager(IAdbClient client, DeviceData device, bool thirdPartyOnly = false, Func syncServiceFactory = null, bool skipInit = false , ILogger logger = null ) { Device = device ?? throw new ArgumentNullException(nameof(device)); Packages = []; @@ -89,13 +81,8 @@ public PackageManager(IAdbClient client, DeviceData device, bool thirdPartyOnly RefreshPackages(); } -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } -#if !HAS_LOGGER -#pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Gets a value indicating whether this package manager only lists third party applications, @@ -438,9 +425,7 @@ protected virtual string SyncPackageToDevice(string localFilePath, Action using AdvancedSharpAdbClient.Exceptions; +using AdvancedSharpAdbClient.Logs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -37,12 +38,10 @@ public partial class DeviceMonitor : IDeviceMonitor private bool disposed = false; -#if HAS_LOGGER /// /// The logger to use when logging messages. /// protected readonly ILogger logger; -#endif /// /// The list of devices currently connected to the Android Debug Bridge. @@ -80,30 +79,18 @@ public partial class DeviceMonitor : IDeviceMonitor /// public event EventHandler DeviceDisconnected; -#if !HAS_LOGGER -#pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// /// Initializes a new instance of the class. /// /// The that manages the connection with the adb server. /// The logger to use when logging. - public DeviceMonitor(IAdbSocket socket -#if HAS_LOGGER - , ILogger logger = null -#endif - ) + public DeviceMonitor(IAdbSocket socket, ILogger logger = null) { Socket = socket ?? throw new ArgumentNullException(nameof(socket)); devices = []; Devices = devices.AsReadOnly(); -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif + this.logger = logger ?? LoggerProvider.CreateLogger(); } -#if !HAS_LOGGER -#pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif /// public ReadOnlyCollection Devices { get; private set; } diff --git a/AdvancedSharpAdbClient/Extensions/LoggerExtensions.cs b/AdvancedSharpAdbClient/Extensions/LoggerExtensions.cs index 89af0cbd..e54c84c7 100644 --- a/AdvancedSharpAdbClient/Extensions/LoggerExtensions.cs +++ b/AdvancedSharpAdbClient/Extensions/LoggerExtensions.cs @@ -1,19 +1,17 @@ -#if HAS_OLDLOGGER -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// -using Microsoft.Extensions.Logging.Internal; using System; +using AdvancedSharpAdbClient.Logs; -namespace Microsoft.Extensions.Logging +namespace AdvancedSharpAdbClient { /// /// ILogger extension methods for common scenarios. /// - public static class LoggerExtensionsEx + public static class LoggerExtensions { - private static readonly Func _messageFormatter = MessageFormatter; - //------------------------------------------DEBUG------------------------------------------// /// @@ -24,8 +22,22 @@ public static class LoggerExtensionsEx /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. /// logger.LogDebug(exception, "Error while processing request from {Address}", address) - public static void LogDebug(this ILogger logger, Exception exception, string message, params object[] args) => + public static void LogDebug(this ILogger logger, Exception exception, string message, params object[] args) + { logger.Log(LogLevel.Debug, exception, message, args); + } + + /// + /// Formats and writes a debug log message. + /// + /// The to write to. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" + /// An object array that contains zero or more objects to format. + /// logger.LogDebug("Processing request from {Address}", address) + public static void LogDebug(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Debug, message, args); + } //------------------------------------------TRACE------------------------------------------// @@ -37,8 +49,22 @@ public static void LogDebug(this ILogger logger, Exception exception, string mes /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. /// logger.LogTrace(exception, "Error while processing request from {Address}", address) - public static void LogTrace(this ILogger logger, Exception exception, string message, params object[] args) => + public static void LogTrace(this ILogger logger, Exception exception, string message, params object[] args) + { logger.Log(LogLevel.Trace, exception, message, args); + } + + /// + /// Formats and writes a trace log message. + /// + /// The to write to. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" + /// An object array that contains zero or more objects to format. + /// logger.LogTrace("Processing request from {Address}", address) + public static void LogTrace(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Trace, message, args); + } //------------------------------------------INFORMATION------------------------------------------// @@ -50,8 +76,22 @@ public static void LogTrace(this ILogger logger, Exception exception, string mes /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. /// logger.LogInformation(exception, "Error while processing request from {Address}", address) - public static void LogInformation(this ILogger logger, Exception exception, string message, params object[] args) => + public static void LogInformation(this ILogger logger, Exception exception, string message, params object[] args) + { logger.Log(LogLevel.Information, exception, message, args); + } + + /// + /// Formats and writes an informational log message. + /// + /// The to write to. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" + /// An object array that contains zero or more objects to format. + /// logger.LogInformation("Processing request from {Address}", address) + public static void LogInformation(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Information, message, args); + } //------------------------------------------WARNING------------------------------------------// @@ -63,86 +103,85 @@ public static void LogInformation(this ILogger logger, Exception exception, stri /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. /// logger.LogWarning(exception, "Error while processing request from {Address}", address) - public static void LogWarning(this ILogger logger, Exception exception, string message, params object[] args) => + public static void LogWarning(this ILogger logger, Exception exception, string message, params object[] args) + { logger.Log(LogLevel.Warning, exception, message, args); - - //------------------------------------------ERROR------------------------------------------// + } /// - /// Formats and writes an error log message. + /// Formats and writes a warning log message. /// /// The to write to. - /// The exception to log. /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. - /// logger.LogError(exception, "Error while processing request from {Address}", address) - public static void LogError(this ILogger logger, Exception exception, string message, params object[] args) => - logger.Log(LogLevel.Error, exception, message, args); + /// logger.LogWarning("Processing request from {Address}", address) + public static void LogWarning(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Warning, message, args); + } - //------------------------------------------CRITICAL------------------------------------------// + //------------------------------------------ERROR------------------------------------------// /// - /// Formats and writes a critical log message. + /// Formats and writes an error log message. /// /// The to write to. /// The exception to log. /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. - /// logger.LogCritical(exception, "Error while processing request from {Address}", address) - public static void LogCritical(this ILogger logger, Exception exception, string message, params object[] args) => - logger.Log(LogLevel.Critical, exception, message, args); + /// logger.LogError(exception, "Error while processing request from {Address}", address) + public static void LogError(this ILogger logger, Exception exception, string message, params object[] args) + { + logger.Log(LogLevel.Error, exception, message, args); + } /// - /// Formats and writes a log message at the specified log level. + /// Formats and writes an error log message. /// /// The to write to. - /// Entry will be written on this level. - /// Format string of the log message. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, string message, params object[] args) => - logger.Log(logLevel, 0, null, message, args); + /// logger.LogError("Processing request from {Address}", address) + public static void LogError(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Error, message, args); + } + + //------------------------------------------CRITICAL------------------------------------------// /// - /// Formats and writes a log message at the specified log level. + /// Formats and writes a critical log message. /// /// The to write to. - /// Entry will be written on this level. - /// The event id associated with the log. - /// Format string of the log message. + /// The exception to log. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, string message, params object[] args) => - logger.Log(logLevel, eventId, null, message, args); + /// logger.LogCritical(exception, "Error while processing request from {Address}", address) + public static void LogCritical(this ILogger logger, Exception exception, string message, params object[] args) + { + logger.Log(LogLevel.Critical, exception, message, args); + } /// - /// Formats and writes a log message at the specified log level. + /// Formats and writes a critical log message. /// /// The to write to. - /// Entry will be written on this level. - /// The exception to log. - /// Format string of the log message. + /// Format string of the log message in message template format. Example: "User {User} logged in from {Address}" /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, Exception exception, string message, params object[] args) => - logger.Log(logLevel, 0, exception, message, args); + /// logger.LogCritical("Processing request from {Address}", address) + public static void LogCritical(this ILogger logger, string message, params object[] args) + { + logger.Log(LogLevel.Critical, message, args); + } /// /// Formats and writes a log message at the specified log level. /// /// The to write to. /// Entry will be written on this level. - /// The event id associated with the log. - /// The exception to log. /// Format string of the log message. /// An object array that contains zero or more objects to format. - public static void Log(this ILogger logger, LogLevel logLevel, EventId eventId, Exception exception, string message, params object[] args) - { - if (logger == null) { throw new ArgumentNullException(nameof(logger)); } - - logger.Log(logLevel, eventId, new FormattedLogValues(message, args), exception, _messageFormatter); - } - - //------------------------------------------HELPERS------------------------------------------// - - private static string MessageFormatter(FormattedLogValues state, Exception error) => state.ToString(); + public static void Log(this ILogger logger, LogLevel logLevel, string message, params object[] args) => + logger.Log(logLevel, null, message, args); } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/AdvancedSharpAdbClient/Logs/Enums/LogLevel.cs b/AdvancedSharpAdbClient/Logs/Enums/LogLevel.cs new file mode 100644 index 00000000..0578c31c --- /dev/null +++ b/AdvancedSharpAdbClient/Logs/Enums/LogLevel.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +namespace AdvancedSharpAdbClient.Logs +{ + /// + /// Defines logging severity levels. + /// + public enum LogLevel : byte + { + /// + /// Logs that contain the most detailed messages. These messages may contain sensitive application data. + /// These messages are disabled by default and should never be enabled in a production environment. + /// + Trace = 0, + + /// + /// Logs that are used for interactive investigation during development. These logs should primarily contain + /// information useful for debugging and have no long-term value. + /// + Debug = 1, + + /// + /// Logs that track the general flow of the application. These logs should have long-term value. + /// + Information = 2, + + /// + /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the + /// application execution to stop. + /// + Warning = 3, + + /// + /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a + /// failure in the current activity, not an application-wide failure. + /// + Error = 4, + + /// + /// Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires + /// immediate attention. + /// + Critical = 5, + + /// + /// Not used for writing log messages. Specifies that a logging category should not write any messages. + /// + None = 6, + } +} diff --git a/AdvancedSharpAdbClient/Logs/Interfaces/ILogger.cs b/AdvancedSharpAdbClient/Logs/Interfaces/ILogger.cs new file mode 100644 index 00000000..fa3460e8 --- /dev/null +++ b/AdvancedSharpAdbClient/Logs/Interfaces/ILogger.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +using System; + +namespace AdvancedSharpAdbClient.Logs +{ + /// + /// Represents a type used to perform logging. + /// + /// Aggregates most logging patterns to a single method. + public interface ILogger + { + /// + /// Formats and writes a log message at the specified log level. + /// + /// Entry will be written on this level. + /// The exception to log. + /// Format string of the log message. + /// An object array that contains zero or more objects to format. + void Log(LogLevel logLevel, Exception exception, string message, params object[] args); + } + + /// + /// A generic interface for logging where the category name is derived from the specified + /// type name. + /// Generally used to enable activation of a named from dependency injection. + /// + /// The type whose name is used for the logger category name. + public interface ILogger : ILogger + { + + } +} diff --git a/AdvancedSharpAdbClient/Logs/Interfaces/ILoggerFactory.cs b/AdvancedSharpAdbClient/Logs/Interfaces/ILoggerFactory.cs new file mode 100644 index 00000000..62f1096b --- /dev/null +++ b/AdvancedSharpAdbClient/Logs/Interfaces/ILoggerFactory.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +using System; + +namespace AdvancedSharpAdbClient.Logs +{ + /// + /// Represents a type used to configure the logging system and create instances of . + /// + public interface ILoggerFactory : IDisposable + { + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// The . + ILogger CreateLogger(string categoryName); + + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// The . + ILogger CreateLogger(); + } +} diff --git a/AdvancedSharpAdbClient/Logs/LoggerProvider.cs b/AdvancedSharpAdbClient/Logs/LoggerProvider.cs new file mode 100644 index 00000000..f2bc3026 --- /dev/null +++ b/AdvancedSharpAdbClient/Logs/LoggerProvider.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +namespace AdvancedSharpAdbClient.Logs +{ + /// + /// Provides a mechanism for creating instances of and classes. + /// + public static class LoggerProvider + { + private static ILoggerFactory _loggerFactory = null; + + /// + /// Sets the current log provider based on logger factory. + /// + /// The logger factory. + public static void SetLogProvider(ILoggerFactory loggerFactory) => _loggerFactory = loggerFactory; + + /// + /// Creates a new instance. + /// + /// The category name for messages produced by the logger. + /// A new instance. + public static ILogger CreateLogger(string category) => _loggerFactory == null ? NullLogger.Instance : _loggerFactory.CreateLogger(category); + + /// + /// Creates a new instance using the full name of the given type. + /// + /// The type. + /// The that was created + public static ILogger CreateLogger() => _loggerFactory == null ? NullLogger.Instance : _loggerFactory.CreateLogger(); + } +} diff --git a/AdvancedSharpAdbClient/Logs/NullLogger.cs b/AdvancedSharpAdbClient/Logs/NullLogger.cs new file mode 100644 index 00000000..229254cc --- /dev/null +++ b/AdvancedSharpAdbClient/Logs/NullLogger.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. +// + +using System; + +namespace AdvancedSharpAdbClient.Logs +{ + /// + /// Minimalistic logger that does nothing. + /// + public class NullLogger : ILogger + { + /// + /// Returns the shared instance of . + /// + public static NullLogger Instance { get; } = new(); + + /// + public void Log(LogLevel logLevel, Exception exception, string message, params object[] args) { } + } + + /// + /// Minimalistic logger that does nothing. + /// + public class NullLogger : NullLogger, ILogger + { + /// + /// Returns an instance of . + /// + /// An instance of . + public static new NullLogger Instance { get; } = new(); + } +} diff --git a/AdvancedSharpAdbClient/Logs/NullLoggerT.cs b/AdvancedSharpAdbClient/Logs/NullLoggerT.cs deleted file mode 100644 index 8d60373b..00000000 --- a/AdvancedSharpAdbClient/Logs/NullLoggerT.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if HAS_OLDLOGGER -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Extensions.Logging; -using System; - -namespace Microsoft.Extensions.Logging.Abstractions -{ - /// - /// Minimalistic logger that does nothing. - /// - public class NullLogger : ILogger - { - /// - /// Returns an instance of . - /// - /// An instance of . - public static readonly NullLogger Instance = new(); - - /// - public IDisposable BeginScope(TState state) => NullScope.Instance; - - /// - /// - /// This method ignores the parameters and does nothing. - /// - public void Log( - LogLevel logLevel, - EventId eventId, - TState state, - Exception exception, - Func formatter) - { - } - - /// - public bool IsEnabled(LogLevel logLevel) => false; - } - - internal sealed class NullScope : IDisposable - { - public static NullScope Instance { get; } = new NullScope(); - - private NullScope() - { - } - - /// - public void Dispose() - { - } - } -} -#endif diff --git a/AdvancedSharpAdbClient/Properties/GlobalUsings.cs b/AdvancedSharpAdbClient/Properties/GlobalUsings.cs index 56cd0031..24e9282d 100644 --- a/AdvancedSharpAdbClient/Properties/GlobalUsings.cs +++ b/AdvancedSharpAdbClient/Properties/GlobalUsings.cs @@ -30,11 +30,6 @@ global using System.Threading.Tasks; #endif -#if HAS_LOGGER -global using Microsoft.Extensions.Logging; -global using Microsoft.Extensions.Logging.Abstractions; -#endif - #if HAS_BUFFERS global using System.Buffers; #endif diff --git a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs index 69265c31..97082d73 100644 --- a/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs +++ b/AdvancedSharpAdbClient/Receivers/ConsoleOutputReceiver.cs @@ -3,6 +3,7 @@ // using AdvancedSharpAdbClient.Exceptions; +using AdvancedSharpAdbClient.Logs; using System.Collections.Generic; using System.IO; using System.Text; @@ -14,46 +15,24 @@ namespace AdvancedSharpAdbClient /// Receives console output, and makes the console output available as a . To /// fetch the console output that was received, used the method. /// - public partial class ConsoleOutputReceiver : MultiLineReceiver + /// The logger to use when logging. + public partial class ConsoleOutputReceiver(ILogger logger = null) : MultiLineReceiver { /// /// The default to use when parsing the output. /// protected const RegexOptions DefaultRegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase; -#if HAS_LOGGER /// /// The logger to use when logging messages. /// - protected readonly ILogger logger; -#endif + protected readonly ILogger logger = logger ?? LoggerProvider.CreateLogger(); /// /// A which receives all output from the device. /// protected readonly StringBuilder output = new(); -#if !HAS_LOGGER -#pragma warning disable CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif - /// - /// Initializes a new instance of the class. - /// - /// The logger to use when logging. - public ConsoleOutputReceiver( -#if HAS_LOGGER - ILogger logger = null -#endif - ) - { -#if HAS_LOGGER - this.logger = logger ?? NullLogger.Instance; -#endif - } -#if !HAS_LOGGER -#pragma warning restore CS1572 // XML 注释中有 param 标记,但是没有该名称的参数 -#endif - /// /// Gets a that represents the current . /// @@ -70,35 +49,27 @@ public virtual void ThrowOnError(string line) { if (line.EndsWith(": not found")) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: '{line}'"); -#endif throw new FileNotFoundException($"The remote execution returned: '{line}'"); } if (line.EndsWith("No such file or directory")) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: {line}"); -#endif throw new FileNotFoundException($"The remote execution returned: '{line}'"); } // for "unknown options" if (line.Contains("Unknown option")) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: {line}"); -#endif throw new UnknownOptionException($"The remote execution returned: '{line}'"); } // for "aborting" commands if (AbortingRegex().IsMatch(line)) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: {line}"); -#endif throw new CommandAbortingException($"The remote execution returned: '{line}'"); } @@ -106,9 +77,7 @@ public virtual void ThrowOnError(string line) // cmd: applet not found if (AppletRegex().IsMatch(line)) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: '{line}'"); -#endif throw new FileNotFoundException($"The remote execution returned: '{line}'"); } @@ -116,9 +85,7 @@ public virtual void ThrowOnError(string line) // workitem: 16822 if (DeniedRegex().IsMatch(line)) { -#if HAS_LOGGER logger.LogWarning($"The remote execution returned: '{line}'"); -#endif throw new PermissionDeniedException($"The remote execution returned: '{line}'"); } } @@ -137,9 +104,7 @@ protected override void ProcessNewLines(IEnumerable lines) continue; } output.AppendLine(line); -#if HAS_LOGGER logger.LogDebug(line); -#endif } } From 243a7efea84b18de7b863c10f7516def900d31d4 Mon Sep 17 00:00:00 2001 From: wherewhere Date: Wed, 27 Sep 2023 17:23:46 +0800 Subject: [PATCH 8/9] Remove CrossPlatformFunc Rename Utilities to Extensions --- .../AdbServerTests.cs | 1 - .../{UtilitiesTests.cs => ExtensionsTests.cs} | 16 +-- AdvancedSharpAdbClient/AdbClient.Async.cs | 4 +- AdvancedSharpAdbClient/AdbClient.cs | 4 +- .../AdbCommandLineClient.Async.cs | 50 ++++++- .../AdbCommandLineClient.cs | 46 ++++++- AdvancedSharpAdbClient/AdbServer.Async.cs | 5 +- AdvancedSharpAdbClient/AdbServer.cs | 15 ++- AdvancedSharpAdbClient/DeviceMonitor.Async.cs | 4 +- AdvancedSharpAdbClient/DeviceMonitor.cs | 2 +- .../Extensions/CrossPlatformFunc.cs | 123 ------------------ .../Extensions/Factories.cs | 7 + .../Extensions/Utilities.cs | 4 +- .../Logs/LogReader.Async.cs | 4 +- AdvancedSharpAdbClient/Logs/LogReader.cs | 2 +- AdvancedSharpAdbClient/Models/DeviceData.cs | 2 +- AdvancedSharpAdbClient/Models/ShellStream.cs | 2 +- AdvancedSharpAdbClient/SyncService.Async.cs | 4 +- AdvancedSharpAdbClient/SyncService.cs | 2 +- AdvancedSharpAdbClient/TcpSocket.Async.cs | 2 +- 20 files changed, 135 insertions(+), 164 deletions(-) rename AdvancedSharpAdbClient.Tests/Extensions/{UtilitiesTests.cs => ExtensionsTests.cs} (62%) delete mode 100644 AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs diff --git a/AdvancedSharpAdbClient.Tests/AdbServerTests.cs b/AdvancedSharpAdbClient.Tests/AdbServerTests.cs index 8aaadb3d..54ec6738 100644 --- a/AdvancedSharpAdbClient.Tests/AdbServerTests.cs +++ b/AdvancedSharpAdbClient.Tests/AdbServerTests.cs @@ -27,7 +27,6 @@ public AdbServerTests() adbSocketFactory = (endPoint) => socket; commandLineClient = new DummyAdbCommandLineClient(); - AdbServer.IsValidAdbFile = commandLineClient.IsValidAdbFile; adbCommandLineClientFactory = (version) => commandLineClient; adbClient = new AdbClient(AdbClient.DefaultEndPoint, adbSocketFactory); diff --git a/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs b/AdvancedSharpAdbClient.Tests/Extensions/ExtensionsTests.cs similarity index 62% rename from AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs rename to AdvancedSharpAdbClient.Tests/Extensions/ExtensionsTests.cs index 325a6753..793d7e4b 100644 --- a/AdvancedSharpAdbClient.Tests/Extensions/UtilitiesTests.cs +++ b/AdvancedSharpAdbClient.Tests/Extensions/ExtensionsTests.cs @@ -4,19 +4,19 @@ namespace AdvancedSharpAdbClient.Tests { /// - /// Tests the class. + /// Tests the class. /// - public class UtilitiesTests + public class ExtensionsTests { [Fact] public void TryParseTest() { - Assert.True(Utilities.TryParse("BootLoader", false, out DeviceState result)); + Assert.True(Extensions.TryParse("BootLoader", false, out DeviceState result)); Assert.Equal(DeviceState.BootLoader, result); - Assert.True(Utilities.TryParse("Bootloader", true, out result)); + Assert.True(Extensions.TryParse("Bootloader", true, out result)); Assert.Equal(DeviceState.BootLoader, result); - Assert.False(Utilities.TryParse("Bootloader", false, out _)); - Assert.False(Utilities.TryParse("Reset", true, out _)); + Assert.False(Extensions.TryParse("Bootloader", false, out _)); + Assert.False(Extensions.TryParse("Reset", true, out _)); } [Fact] @@ -28,13 +28,13 @@ public void IsNullOrWhiteSpaceTest() [Fact] public void JoinTest() => - Assert.Equal("Hello World!", Utilities.Join(" ", ["Hello", "World!"])); + Assert.Equal("Hello World!", Extensions.Join(" ", ["Hello", "World!"])); [Fact] public void FromUnixTimeSecondsTest() { DateTimeOffset time = new(new DateTime(2022, 6, 1, 12, 10, 34, DateTimeKind.Utc)); - Assert.Equal(time, Utilities.FromUnixTimeSeconds(1654085434)); + Assert.Equal(time, Extensions.FromUnixTimeSeconds(1654085434)); } [Fact] diff --git a/AdvancedSharpAdbClient/AdbClient.Async.cs b/AdvancedSharpAdbClient/AdbClient.Async.cs index 7c0b8ca5..70486bdc 100644 --- a/AdvancedSharpAdbClient/AdbClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbClient.Async.cs @@ -380,7 +380,7 @@ protected async Task RootAsync(string request, DeviceData device, CancellationTo { // 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. - Utilities.Delay(3000, cancellationToken).GetAwaiter().GetResult(); + Extensions.Delay(3000, cancellationToken).GetAwaiter().GetResult(); } } @@ -985,7 +985,7 @@ public async Task SendTextAsync(DeviceData device, string text, CancellationToke public async Task ClearInputAsync(DeviceData device, int charCount, CancellationToken cancellationToken = default) { await SendKeyEventAsync(device, "KEYCODE_MOVE_END", cancellationToken); - await ExecuteRemoteCommandAsync("input keyevent " + Utilities.Join(" ", Enumerable.Repeat("KEYCODE_DEL ", charCount)), device, null, cancellationToken); + await ExecuteRemoteCommandAsync("input keyevent " + Extensions.Join(" ", Enumerable.Repeat("KEYCODE_DEL ", charCount)), device, null, cancellationToken); } /// diff --git a/AdvancedSharpAdbClient/AdbClient.cs b/AdvancedSharpAdbClient/AdbClient.cs index 05fdbe16..906b35d0 100644 --- a/AdvancedSharpAdbClient/AdbClient.cs +++ b/AdvancedSharpAdbClient/AdbClient.cs @@ -519,7 +519,7 @@ protected void Root(string request, DeviceData device) #if HAS_PROCESS && !WINDOWS_UWP Thread.Sleep(3000); #else - Utilities.Delay(3000).GetAwaiter().GetResult(); + Extensions.Delay(3000).GetAwaiter().GetResult(); #endif } } @@ -1042,7 +1042,7 @@ public void SendText(DeviceData device, string text) public void ClearInput(DeviceData device, int charCount) { SendKeyEvent(device, "KEYCODE_MOVE_END"); - ExecuteRemoteCommand("input keyevent " + Utilities.Join(" ", Enumerable.Repeat("KEYCODE_DEL ", charCount)), device, null); + ExecuteRemoteCommand("input keyevent " + Extensions.Join(" ", Enumerable.Repeat("KEYCODE_DEL ", charCount)), device, null); } /// diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs index b6ed11cf..1f003f11 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.Async.cs @@ -123,10 +123,58 @@ protected virtual async Task RunAdbProcessInnerAsync(string command, List + /// Runs process, invoking a specific command, and reads the standard output and standard error output. + /// + /// The return code of the process. + protected virtual async Task RunProcessAsync(string filename, string command, List errorOutput, List standardOutput, CancellationToken cancellationToken = default) + { +#if HAS_PROCESS + ProcessStartInfo psi = new(filename, command) + { + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true + }; + + using Process process = Process.Start(psi); + string standardErrorString = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + string standardOutputString = await process.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false); + + errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + + standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + +#if NET5_0_OR_GREATER + using (CancellationTokenSource completionSource = new(TimeSpan.FromMilliseconds(5000))) + { + await process.WaitForExitAsync(completionSource.Token); + if (!process.HasExited) + { + process.Kill(); + } + } +#else + // get the return code from the process + if (!process.WaitForExit(5000)) + { + process.Kill(); + } +#endif + return process.ExitCode; +#else + TaskCompletionSource source = new(); + source.SetException(new PlatformNotSupportedException()); + return await source.Task; +#endif + } } } #endif \ No newline at end of file diff --git a/AdvancedSharpAdbClient/AdbCommandLineClient.cs b/AdvancedSharpAdbClient/AdbCommandLineClient.cs index 4aea2e19..0d121032 100644 --- a/AdvancedSharpAdbClient/AdbCommandLineClient.cs +++ b/AdvancedSharpAdbClient/AdbCommandLineClient.cs @@ -23,6 +23,8 @@ public partial class AdbCommandLineClient : IAdbCommandLineClient /// protected const string AdbVersionPattern = "^.*(\\d+)\\.(\\d+)\\.(\\d+)$"; + private static readonly char[] separator = ['\r', '\n']; + /// /// The logger to use when logging messages. /// @@ -43,8 +45,8 @@ public AdbCommandLineClient(string adbPath, bool isForce = false, ILogger - public virtual bool IsValidAdbFile(string adbPath) => CrossPlatformFunc.CheckFileExists(adbPath); + public virtual bool IsValidAdbFile(string adbPath) => Factories.CheckFileExists(adbPath); /// /// Parses the output of the adb.exe version command and determines the adb version. @@ -213,11 +215,47 @@ protected virtual int RunAdbProcessInner(string command, List errorOutpu { ExceptionExtensions.ThrowIfNull(command); - int status = CrossPlatformFunc.RunProcess(AdbPath, command, errorOutput, standardOutput); + int status = RunProcess(AdbPath, command, errorOutput, standardOutput); return status; } + /// + /// Runs process, invoking a specific command, and reads the standard output and standard error output. + /// + /// The return code of the process. + protected virtual int RunProcess(string filename, string command, List errorOutput, List standardOutput) + { +#if HAS_PROCESS + ProcessStartInfo psi = new(filename, command) + { + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true + }; + + using Process process = Process.Start(psi); + string standardErrorString = process.StandardError.ReadToEnd(); + string standardOutputString = process.StandardOutput.ReadToEnd(); + + errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + + standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + + // get the return code from the process + if (!process.WaitForExit(5000)) + { + process.Kill(); + } + + return process.ExitCode; +#else + throw new PlatformNotSupportedException(); +#endif + } + #if NET7_0_OR_GREATER [GeneratedRegex(AdbVersionPattern)] private static partial Regex AdbVersionRegex(); diff --git a/AdvancedSharpAdbClient/AdbServer.Async.cs b/AdvancedSharpAdbClient/AdbServer.Async.cs index d5a43af5..f69838d3 100644 --- a/AdvancedSharpAdbClient/AdbServer.Async.cs +++ b/AdvancedSharpAdbClient/AdbServer.Async.cs @@ -19,6 +19,7 @@ public virtual async Task StartServerAsync(string adbPath, bo Version commandLineVersion = null; IAdbCommandLineClient commandLineClient = adbCommandLineClientFactory(adbPath); + IsValidAdbFile = commandLineClient.IsValidAdbFile; if (commandLineClient.IsValidAdbFile(adbPath)) { @@ -73,7 +74,7 @@ public virtual async Task RestartServerAsync(string adbPath, } ManualResetEvent manualResetEvent = null; - await Utilities.Run(() => + await Extensions.Run(() => { lock (RestartLock) { @@ -81,7 +82,7 @@ await Utilities.Run(() => } }, cancellationToken); - _ = Utilities.Run(() => + _ = Extensions.Run(() => { lock (RestartLock) { diff --git a/AdvancedSharpAdbClient/AdbServer.cs b/AdvancedSharpAdbClient/AdbServer.cs index a6bc7d77..74813ad0 100644 --- a/AdvancedSharpAdbClient/AdbServer.cs +++ b/AdvancedSharpAdbClient/AdbServer.cs @@ -32,7 +32,7 @@ public partial class AdbServer(IAdbClient adbClient, FuncNo connection could be made because the target computer actively refused it.This usually /// results from trying to connect to a service that is inactive on the foreign host—that is, /// one with no server application running. - internal const int ConnectionRefused = 10061; + public const int ConnectionRefused = 10061; /// /// The error code that is returned by the when the connection was reset by the peer. @@ -41,12 +41,7 @@ public partial class AdbServer(IAdbClient adbClient, Func - internal const int ConnectionReset = 10054; - - /// - /// Throws an error if the path does not point to a valid instance of adb.exe. - /// - internal static Func IsValidAdbFile = CrossPlatformFunc.CheckFileExists; + public const int ConnectionReset = 10054; /// /// A lock used to ensure only one caller at a time can attempt to restart adb. @@ -99,6 +94,11 @@ public AdbServer(Func adbCommandLineClientFactory /// public static IAdbServer Instance { get; set; } = new AdbServer(); + /// + /// Throws an error if the path does not point to a valid instance of adb.exe. + /// + protected static Func IsValidAdbFile { get; set; } = Factories.CheckFileExists; + /// public virtual StartServerResult StartServer(string adbPath, bool restartServerIfNewer) { @@ -106,6 +106,7 @@ public virtual StartServerResult StartServer(string adbPath, bool restartServerI Version commandLineVersion = null; IAdbCommandLineClient commandLineClient = adbCommandLineClientFactory(adbPath); + IsValidAdbFile = commandLineClient.IsValidAdbFile; if (commandLineClient.IsValidAdbFile(adbPath)) { diff --git a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs index 38509d3f..0afff082 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.Async.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.Async.cs @@ -35,10 +35,10 @@ public virtual async Task StartAsync(CancellationToken cancellationToken = defau { _ = firstDeviceListParsed.Reset(); - monitorTask = Utilities.Run(() => DeviceMonitorLoopAsync(monitorTaskCancellationTokenSource.Token), cancellationToken); + monitorTask = Extensions.Run(() => DeviceMonitorLoopAsync(monitorTaskCancellationTokenSource.Token), cancellationToken); // Wait for the worker thread to have read the first list of devices. - _ = await Utilities.Run(firstDeviceListParsed.WaitOne, cancellationToken); + _ = await Extensions.Run(firstDeviceListParsed.WaitOne, cancellationToken); } } diff --git a/AdvancedSharpAdbClient/DeviceMonitor.cs b/AdvancedSharpAdbClient/DeviceMonitor.cs index 52cfb2f3..3af58648 100644 --- a/AdvancedSharpAdbClient/DeviceMonitor.cs +++ b/AdvancedSharpAdbClient/DeviceMonitor.cs @@ -115,7 +115,7 @@ public virtual void Start() { _ = firstDeviceListParsed.Reset(); - monitorTask = Utilities.Run(() => DeviceMonitorLoopAsync(monitorTaskCancellationTokenSource.Token)); + monitorTask = Extensions.Run(() => DeviceMonitorLoopAsync(monitorTaskCancellationTokenSource.Token)); // Wait for the worker thread to have read the first list of devices. _ = firstDeviceListParsed.WaitOne(); diff --git a/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs b/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs deleted file mode 100644 index e21642dd..00000000 --- a/AdvancedSharpAdbClient/Extensions/CrossPlatformFunc.cs +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. -// - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Threading; - -namespace AdvancedSharpAdbClient -{ - /// - /// The functions which are used by the class, but which are platform-specific. - /// - public static class CrossPlatformFunc - { - private static readonly char[] separator = ['\r', '\n']; - - /// - /// Determines whether the specified file exists. - /// - public static Func CheckFileExists { get; set; } = File.Exists; - - /// - /// Runs process, invoking a specific command, and reads the standard output and standard error output. - /// - /// The return code of the process. - public static Func, List, int> RunProcess { get; set; } = (string filename, string command, List errorOutput, List standardOutput) => - { -#if HAS_PROCESS - ProcessStartInfo psi = new(filename, command) - { - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - UseShellExecute = false, - RedirectStandardError = true, - RedirectStandardOutput = true - }; - - using Process process = Process.Start(psi); - string standardErrorString = process.StandardError.ReadToEnd(); - string standardOutputString = process.StandardOutput.ReadToEnd(); - - errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - - standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - - // get the return code from the process - if (!process.WaitForExit(5000)) - { - process.Kill(); - } - - return process.ExitCode; -#else - throw new PlatformNotSupportedException(); -#endif - }; - -#if HAS_TASK -#if NETFRAMEWORK && !NET40_OR_GREATER - /// - /// Encapsulates a method that has five parameters and returns a value of the type specified by the parameter. - /// - /// The return value of the method that this delegate encapsulates. - public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); -#endif - - /// - /// Runs process, invoking a specific command, and reads the standard output and standard error output. - /// - /// The return code of the process. - public static Func, List, CancellationToken, Task> RunProcessAsync { get; set; } = -#if HAS_PROCESS - async -#endif - (string filename, string command, List errorOutput, List standardOutput, CancellationToken cancellationToken) => - { -#if HAS_PROCESS - ProcessStartInfo psi = new(filename, command) - { - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - UseShellExecute = false, - RedirectStandardError = true, - RedirectStandardOutput = true - }; - - using Process process = Process.Start(psi); - string standardErrorString = await process.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - string standardOutputString = await process.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - - errorOutput?.AddRange(standardErrorString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - - standardOutput?.AddRange(standardOutputString.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - -#if NET5_0_OR_GREATER - using (CancellationTokenSource completionSource = new(TimeSpan.FromMilliseconds(5000))) - { - await process.WaitForExitAsync(completionSource.Token); - if (!process.HasExited) - { - process.Kill(); - } - } -#else - // get the return code from the process - if (!process.WaitForExit(5000)) - { - process.Kill(); - } -#endif - return process.ExitCode; -#else - TaskCompletionSource source = new(); - source.SetException(new PlatformNotSupportedException()); - return source.Task; -#endif - }; -#endif - } -} diff --git a/AdvancedSharpAdbClient/Extensions/Factories.cs b/AdvancedSharpAdbClient/Extensions/Factories.cs index 957f1f4e..036293c9 100644 --- a/AdvancedSharpAdbClient/Extensions/Factories.cs +++ b/AdvancedSharpAdbClient/Extensions/Factories.cs @@ -3,6 +3,7 @@ // using System; +using System.IO; using System.Net; namespace AdvancedSharpAdbClient @@ -14,6 +15,11 @@ public static class Factories { static Factories() => Reset(); + /// + /// Determines whether the specified file exists. + /// + public static Func CheckFileExists { get; set; } + /// /// Gets or sets a delegate which creates a new instance of the class. /// @@ -45,6 +51,7 @@ public static class Factories /// public static void Reset() { + CheckFileExists = File.Exists; AdbSocketFactory = (endPoint) => new AdbSocket(endPoint); AdbClientFactory = (endPoint) => new AdbClient(endPoint, AdbSocketFactory); AdbCommandLineClientFactory = (path) => new AdbCommandLineClient(path); diff --git a/AdvancedSharpAdbClient/Extensions/Utilities.cs b/AdvancedSharpAdbClient/Extensions/Utilities.cs index 9c878119..273a24b4 100644 --- a/AdvancedSharpAdbClient/Extensions/Utilities.cs +++ b/AdvancedSharpAdbClient/Extensions/Utilities.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) The Android Open Source Project, Ryan Conrad, Quamotion, yungd1plomat, wherewhere. All rights reserved. // @@ -13,7 +13,7 @@ namespace AdvancedSharpAdbClient { - internal static class Utilities + internal static class Extensions { /// /// Converts the string representation of the name or numeric value of one or more diff --git a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs index 1c2947c9..d224a321 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.Async.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.Async.cs @@ -94,7 +94,7 @@ public async Task ReadEntryAsync(CancellationToken cancellationToken = return null; } - DateTimeOffset timestamp = Utilities.FromUnixTimeSeconds(sec); + DateTimeOffset timestamp = Extensions.FromUnixTimeSeconds(sec); switch ((LogId)id) { @@ -213,7 +213,7 @@ await stream.ReadAsync(data.AsMemory(totalRead, count - totalRead), cancellation #elif !NET35 await stream.ReadAsync(data, totalRead, count - totalRead, cancellationToken).ConfigureAwait(false) #else - await Utilities.Run(() => stream.Read(data, totalRead, count - totalRead)).ConfigureAwait(false) + await Extensions.Run(() => stream.Read(data, totalRead, count - totalRead)).ConfigureAwait(false) #endif ) > 0) { diff --git a/AdvancedSharpAdbClient/Logs/LogReader.cs b/AdvancedSharpAdbClient/Logs/LogReader.cs index 256a44fa..1532b639 100644 --- a/AdvancedSharpAdbClient/Logs/LogReader.cs +++ b/AdvancedSharpAdbClient/Logs/LogReader.cs @@ -100,7 +100,7 @@ public virtual LogEntry ReadEntry() return null; } - DateTimeOffset timestamp = Utilities.FromUnixTimeSeconds(sec); + DateTimeOffset timestamp = Extensions.FromUnixTimeSeconds(sec); switch ((LogId)id) { diff --git a/AdvancedSharpAdbClient/Models/DeviceData.cs b/AdvancedSharpAdbClient/Models/DeviceData.cs index 659c7ca1..ceeb94e0 100644 --- a/AdvancedSharpAdbClient/Models/DeviceData.cs +++ b/AdvancedSharpAdbClient/Models/DeviceData.cs @@ -132,7 +132,7 @@ internal static DeviceState GetStateFromString(string state) else { // Else, we try to match a value of the DeviceState enumeration. - if (!Utilities.TryParse(state, true, out value)) + if (!Extensions.TryParse(state, true, out value)) { value = DeviceState.Unknown; } diff --git a/AdvancedSharpAdbClient/Models/ShellStream.cs b/AdvancedSharpAdbClient/Models/ShellStream.cs index 664c837c..06090f87 100644 --- a/AdvancedSharpAdbClient/Models/ShellStream.cs +++ b/AdvancedSharpAdbClient/Models/ShellStream.cs @@ -215,7 +215,7 @@ async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToke #elif !NET35 await Inner.ReadAsync(buffer, offset + 1, count - 1, cancellationToken).ConfigureAwait(false); #else - await Utilities.Run(() => Inner.Read(buffer, offset + 1, count - 1)).ConfigureAwait(false); + await Extensions.Run(() => Inner.Read(buffer, offset + 1, count - 1)).ConfigureAwait(false); #endif read++; pendingByte = null; diff --git a/AdvancedSharpAdbClient/SyncService.Async.cs b/AdvancedSharpAdbClient/SyncService.Async.cs index 9c092210..affaef26 100644 --- a/AdvancedSharpAdbClient/SyncService.Async.cs +++ b/AdvancedSharpAdbClient/SyncService.Async.cs @@ -200,7 +200,7 @@ public virtual async Task PullAsync(string remoteFilePath, Stream stream, IProgr #elif !NET35 await stream.WriteAsync(buffer, 0, size, cancellationToken); #else - await Utilities.Run(() => stream.Write(buffer, 0, size)); + await Extensions.Run(() => stream.Write(buffer, 0, size)); #endif totalBytesRead += size; @@ -311,7 +311,7 @@ private async Task ReadStatisticsAsync(FileStatistics value, CancellationToken c value.FileMode = (UnixFileMode)BitConverter.ToInt32(statResult, 0); value.Size = BitConverter.ToInt32(statResult, 4); - value.Time = Utilities.FromUnixTimeSeconds(BitConverter.ToInt32(statResult, 8)); + value.Time = Extensions.FromUnixTimeSeconds(BitConverter.ToInt32(statResult, 8)); } } } diff --git a/AdvancedSharpAdbClient/SyncService.cs b/AdvancedSharpAdbClient/SyncService.cs index d29577ab..afd58c67 100644 --- a/AdvancedSharpAdbClient/SyncService.cs +++ b/AdvancedSharpAdbClient/SyncService.cs @@ -376,7 +376,7 @@ private void ReadStatistics(FileStatistics value) value.FileMode = (UnixFileMode)BitConverter.ToInt32(statResult, 0); value.Size = BitConverter.ToInt32(statResult, 4); - value.Time = Utilities.FromUnixTimeSeconds(BitConverter.ToInt32(statResult, 8)); + value.Time = Extensions.FromUnixTimeSeconds(BitConverter.ToInt32(statResult, 8)); } } } diff --git a/AdvancedSharpAdbClient/TcpSocket.Async.cs b/AdvancedSharpAdbClient/TcpSocket.Async.cs index d4387163..5f503bb7 100644 --- a/AdvancedSharpAdbClient/TcpSocket.Async.cs +++ b/AdvancedSharpAdbClient/TcpSocket.Async.cs @@ -18,7 +18,7 @@ public virtual async Task SendAsync(byte[] buffer, int offset, int size, So #else /// public virtual async Task SendAsync(byte[] buffer, int offset, int size, SocketFlags socketFlags, CancellationToken cancellationToken = default) => - await Utilities.Run(() => Send(buffer, offset, size, socketFlags), cancellationToken); + await Extensions.Run(() => Send(buffer, offset, size, socketFlags), cancellationToken); #endif #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER From 1dd979eda01a32f95bbc5ab4399da681231e2c0c Mon Sep 17 00:00:00 2001 From: wherewhere Date: Wed, 27 Sep 2023 17:28:19 +0800 Subject: [PATCH 9/9] Use format when log --- AdvancedSharpAdbClient/AdbSocket.Async.cs | 2 +- .../DeviceCommands/PackageManager.Async.cs | 8 ++++---- AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/AdvancedSharpAdbClient/AdbSocket.Async.cs b/AdvancedSharpAdbClient/AdbSocket.Async.cs index 8cc83f7e..358927e9 100644 --- a/AdvancedSharpAdbClient/AdbSocket.Async.cs +++ b/AdvancedSharpAdbClient/AdbSocket.Async.cs @@ -264,7 +264,7 @@ protected virtual async Task ReadAdbResponseInnerAsync(Cancellation { string message = await ReadStringAsync(cancellationToken); rasps.Message = message; - logger.LogError($"Got reply '{ReplyToString(reply)}', diag='{rasps.Message}'"); + logger.LogError("Got reply '{0}', diag='{1}'", ReplyToString(reply), rasps.Message); } return rasps; diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs index c5b58471..5ec44a81 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.Async.cs @@ -358,7 +358,7 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa // workitem: 19711 string remoteFilePath = LinuxPath.Combine(TempInstallationDirectory, packageFileName); - logger.LogDebug(packageFileName, $"Uploading {packageFileName} onto device '{Device.Serial}'"); + logger.LogDebug("Uploading {0} onto device '{1}'", packageFileName, Device.Serial); using (ISyncService sync = syncServiceFactory(client, Device)) { @@ -372,7 +372,7 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa #endif using Stream stream = File.OpenRead(localFilePath); - logger.LogDebug($"Uploading file onto device '{Device.Serial}'"); + logger.LogDebug("Uploading file onto device '{0}'", Device.Serial); // As C# can't use octal, the octal literal 666 (rw-Permission) is here converted to decimal (438) await sync.PushAsync(stream, remoteFilePath, 438, File.GetLastWriteTime(localFilePath), null, cancellationToken); @@ -382,7 +382,7 @@ protected virtual async Task SyncPackageToDeviceAsync(string localFilePa } catch (IOException e) { - logger.LogError(e, $"Unable to open sync connection! reason: {e.Message}"); + logger.LogError(e, "Unable to open sync connection! reason: {0}", e.Message); throw; } finally @@ -407,7 +407,7 @@ protected virtual async Task RemoveRemotePackageAsync(string remoteFilePath, Can } catch (IOException e) { - logger.LogError(e, $"Failed to delete temporary package: {e.Message}"); + logger.LogError(e, "Failed to delete temporary package: {0}", e.Message); throw; } } diff --git a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs index 8439f9ef..9e5694c4 100644 --- a/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs +++ b/AdvancedSharpAdbClient/DeviceCommands/PackageManager.cs @@ -425,7 +425,7 @@ protected virtual string SyncPackageToDevice(string localFilePath, Action