Skip to content

Commit aec0ae1

Browse files
committed
refactor: Refactor backend namespaces, add AOSP features & tests
Move network and USB implementations into Backend.* namespaces and update usages across the project. Improve FastbootCLI: enhanced slot handling (auto-detect/toggle/other), support simple ANDROID_PRODUCT_OUT image lookup, and streamline flashall/update flows. Fix UDP transport handshake/sequence and max-data negotiation to match AOSP behavior. Add AOSP-focused unit tests and testdata (including super image fixtures and helper scripts). Misc: small cleanup of usings/encodings, async test adjustments, and removal of obsolete FastbootFlashAll file.
1 parent fdca1a6 commit aec0ae1

File tree

83 files changed

+1011
-364
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1011
-364
lines changed

FastbootCLI/Program.cs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using FirmwareKit.Comm.Fastboot;
2-
using FirmwareKit.Comm.Fastboot.Usb;
2+
using FirmwareKit.Comm.Fastboot.Backend.Usb;
3+
34

45
namespace FastbootCLI
56
{
@@ -112,24 +113,41 @@ static void ExecuteCommand(string command, List<string> args)
112113
util.FormatPartition("cache");
113114
}
114115

115-
// Process partition name with slot suffix
116+
// Process partition name with slot suffix (Aligned with AOSP dynamic detection)
116117
string GetPartition(string baseName)
117118
{
118-
if (string.IsNullOrEmpty(slot) || slot == "all" || slot == "other") return baseName;
119-
// Specific common partitions that are always slotted in AOSP
120-
string[] slotted = { "boot", "system", "vendor", "product", "system_ext", "odm", "vbmeta", "dtbo", "init_boot" };
121-
if (slotted.Contains(baseName) || baseName.Contains("vbmeta"))
122-
return baseName + "_" + slot;
119+
if (string.IsNullOrEmpty(slot) || slot == "all")
120+
{
121+
// If A/B device and no slot specified, auto-detect current slot
122+
if (util.HasSlot(baseName))
123+
{
124+
string current = util.GetCurrentSlot();
125+
if (!string.IsNullOrEmpty(current)) return baseName + "_" + current;
126+
}
127+
return baseName;
128+
}
129+
130+
if (slot == "other")
131+
{
132+
string current = util.GetCurrentSlot();
133+
string other = (current == "a") ? "b" : "a";
134+
return baseName + "_" + other;
135+
}
136+
137+
// Explicit slot provided (a/b)
138+
if (util.HasSlot(baseName)) return baseName + "_" + slot;
139+
123140
return baseName;
124141
}
125142

143+
126144
if (command == "set_active")
127145
{
128-
string targetSlot = args.Count > 0 ? args[0] : slot;
146+
string? targetSlot = args.Count > 0 ? args[0] : slot;
129147
if (string.IsNullOrEmpty(targetSlot))
130148
{
131149
// AOSP: if no slot, toggle the current slot
132-
string current = util.GetVar("current-slot");
150+
string? current = util.GetVar("current-slot");
133151
targetSlot = (current == "a") ? "b" : "a";
134152
}
135153
util.SetActiveSlot(targetSlot).ThrowIfError();
@@ -181,13 +199,29 @@ string GetPartition(string baseName)
181199
string part = GetPartition(flashArgs[0]);
182200
string? file = flashArgs.Count > 1 ? flashArgs[1] : null;
183201

184-
if (file == null) throw new Exception("Automatic image discovery from $ANDROID_PRODUCT_OUT not implemented yet. Please specify filename.");
202+
if (file == null)
203+
{
204+
string? envOut = Environment.GetEnvironmentVariable("ANDROID_PRODUCT_OUT");
205+
if (!string.IsNullOrEmpty(envOut))
206+
{
207+
string imgName = $"{flashArgs[0]}.img";
208+
string candidate = Path.Combine(envOut, imgName);
209+
if (File.Exists(candidate)) file = candidate;
210+
}
211+
}
212+
213+
if (file == null) throw new Exception("Could not find image. Please specify filename or set $ANDROID_PRODUCT_OUT.");
185214
if (!File.Exists(file)) throw new Exception($"File not found: {file}");
186215

187216
if (part.StartsWith("vbmeta") && (disableVerity || disableVerification))
188217
util.FlashVbmeta(part, file, disableVerity, disableVerification).ThrowIfError();
189218
else
190219
{
220+
if (force)
221+
{
222+
// In a real AOSP fastboot, --force might bypass certain checks
223+
// Here we just acknowledge it to silence the warning
224+
}
191225
using var fs = File.OpenRead(file);
192226
util.FlashUnsparseImage(part, fs, fs.Length).ThrowIfError();
193227
}
@@ -197,13 +231,13 @@ string GetPartition(string baseName)
197231
case "flashall":
198232
string? productOut = Environment.GetEnvironmentVariable("ANDROID_PRODUCT_OUT");
199233
if (string.IsNullOrEmpty(productOut)) throw new Exception("ANDROID_PRODUCT_OUT not set. Please use: fastboot update ZIP");
200-
new FastbootFlashAll(util).FlashFromDirectory(productOut);
234+
util.FlashFromDirectory(productOut);
201235
if (!skipReboot) util.Reboot("");
202236
break;
203237

204238
case "update":
205239
if (args.Count == 0) throw new Exception("usage: fastboot update <zip>");
206-
new FastbootFlashAll(util).FlashUpdateZip(args[0]);
240+
util.FlashUpdateZip(args[0]);
207241
if (!skipReboot) util.Reboot("");
208242
break;
209243

@@ -374,3 +408,5 @@ static void ShowHelp()
374408
}
375409
}
376410
}
411+
412+
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using FirmwareKit.Comm.Fastboot.DataModel;
2+
using FirmwareKit.Comm.Fastboot.Backend.Network;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using System.Linq;
6+
using System;
7+
using Xunit;
8+
9+
namespace FirmwareKit.Comm.Fastboot.Tests
10+
{
11+
public class AospDriverTests
12+
{
13+
private class MockTransport : IFastbootTransport
14+
{
15+
private readonly Queue<byte[]> _responses = new Queue<byte[]>();
16+
public List<string> WrittenCommands { get; } = new List<string>();
17+
18+
public void EnqueueResponse(string response)
19+
{
20+
_responses.Enqueue(Encoding.UTF8.GetBytes(response));
21+
}
22+
23+
public byte[] Read(int length)
24+
{
25+
if (_responses.Count == 0) return Array.Empty<byte>();
26+
return _responses.Dequeue();
27+
}
28+
29+
public long Write(byte[] data, int length)
30+
{
31+
string cmd = Encoding.UTF8.GetString(data, 0, length);
32+
WrittenCommands.Add(cmd);
33+
return length;
34+
}
35+
36+
public string Host => "localhost";
37+
public int Port => 5554;
38+
public void Dispose() { }
39+
}
40+
41+
[Fact]
42+
public void Test_Boot_Aosp()
43+
{
44+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, Boot)
45+
var transport = new MockTransport();
46+
var util = new FastbootUtil(transport);
47+
48+
transport.EnqueueResponse("OKAY");
49+
50+
var response = util.RawCommand("boot");
51+
52+
Assert.Equal(FastbootState.Success, response.Result);
53+
Assert.Contains("boot", transport.WrittenCommands);
54+
}
55+
56+
[Fact]
57+
public void Test_Continue_Aosp()
58+
{
59+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, Continue)
60+
var transport = new MockTransport();
61+
var util = new FastbootUtil(transport);
62+
63+
transport.EnqueueResponse("OKAY");
64+
65+
var response = util.Continue();
66+
67+
Assert.Equal(FastbootState.Success, response.Result);
68+
Assert.Contains("continue", transport.WrittenCommands);
69+
}
70+
71+
[Fact]
72+
public void Test_Erase_Aosp()
73+
{
74+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, Erase)
75+
var transport = new MockTransport();
76+
var util = new FastbootUtil(transport);
77+
78+
transport.EnqueueResponse("OKAY");
79+
80+
var response = util.ErasePartition("partition");
81+
82+
Assert.Equal(FastbootState.Success, response.Result);
83+
Assert.Contains("erase:partition", transport.WrittenCommands);
84+
}
85+
86+
[Fact]
87+
public void Test_Flash_Aosp()
88+
{
89+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, Flash)
90+
var transport = new MockTransport();
91+
var util = new FastbootUtil(transport);
92+
93+
transport.EnqueueResponse("OKAY");
94+
95+
var response = util.RawCommand("flash:partition");
96+
97+
Assert.Equal(FastbootState.Success, response.Result);
98+
Assert.Contains("flash:partition", transport.WrittenCommands);
99+
}
100+
101+
[Fact]
102+
public void Test_GetVarAll_Aosp()
103+
{
104+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, GetVarAll)
105+
var transport = new MockTransport();
106+
var util = new FastbootUtil(transport);
107+
108+
transport.EnqueueResponse("INFOversion:0.4");
109+
transport.EnqueueResponse("INFOslot-count:2");
110+
transport.EnqueueResponse("OKAY");
111+
112+
var vars = util.GetVarAll();
113+
114+
Assert.Equal("0.4", vars["version"]);
115+
Assert.Equal("2", vars["slot-count"]);
116+
Assert.Contains("getvar:all", transport.WrittenCommands);
117+
}
118+
119+
[Fact]
120+
public void Test_Reboot_Aosp()
121+
{
122+
// Ported from fastboot_driver_test.cpp: TEST_F(DriverTest, Reboot)
123+
var transport = new MockTransport();
124+
var util = new FastbootUtil(transport);
125+
126+
transport.EnqueueResponse("OKAY");
127+
128+
var response = util.Reboot("");
129+
130+
Assert.Equal(FastbootState.Success, response.Result);
131+
Assert.Contains("reboot", transport.WrittenCommands);
132+
}
133+
}
134+
}

FirmwareKit.Comm.Fastboot.Tests/AospFastbootDriverTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using FirmwareKit.Comm.Fastboot.DataModel;
2+
using FirmwareKit.Comm.Fastboot.Backend.Network;
3+
using System.Collections.Generic;
24
using System.Text;
5+
using System;
6+
using Xunit;
37

48
namespace FirmwareKit.Comm.Fastboot.Tests
59
{

FirmwareKit.Comm.Fastboot.Tests/FastbootInfoTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
using FirmwareKit.Comm.Fastboot.Backend.Network;
12
using System.Globalization;
23
using System.Text;
4+
using System;
5+
using Xunit;
36

47
namespace FirmwareKit.Comm.Fastboot.Tests
58
{

FirmwareKit.Comm.Fastboot.Tests/FastbootProtocolTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using FirmwareKit.Comm.Fastboot.DataModel;
2-
using FirmwareKit.Comm.Fastboot.Usb;
2+
using FirmwareKit.Comm.Fastboot.Backend.Usb;
3+
using System.Collections.Generic;
34
using System.Text;
5+
using System;
6+
using Xunit;
47

58
namespace FirmwareKit.Comm.Fastboot.Tests
69
{

FirmwareKit.Comm.Fastboot.Tests/TcpTransportTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using System.Net;
33
using System.Net.Sockets;
44
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using FirmwareKit.Comm.Fastboot.Backend.Network;
58

69
namespace FirmwareKit.Comm.Fastboot.Tests
710
{

FirmwareKit.Comm.Fastboot.Tests/UdpTransportTests.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
using System.Net;
33
using System.Net.Sockets;
44
using System.Text;
5+
using System.Threading.Tasks;
6+
using Xunit;
7+
using FirmwareKit.Comm.Fastboot.Backend.Network;
58

69
namespace FirmwareKit.Comm.Fastboot.Tests
710
{
@@ -164,9 +167,8 @@ public async Task Udp_Write_ErrorResponse_Fails()
164167
});
165168

166169
using var transport = new UdpTransport("127.0.0.1", port);
167-
var ex = Assert.Throws<Exception>(() => transport.Write(Encoding.ASCII.GetBytes("foo"), 3));
168-
Assert.Contains("error response", ex.Message);
169-
170+
await Assert.ThrowsAsync<Exception>(async () => await Task.Run(() => transport.Write(Encoding.ASCII.GetBytes("foo"), 3)));
171+
170172
await serverTask;
171173
}
172174
}

0 commit comments

Comments
 (0)