Skip to content

Commit c2cb0d5

Browse files
committed
Assembly stores progress
1 parent be10e4c commit c2cb0d5

File tree

8 files changed

+154
-10
lines changed

8 files changed

+154
-10
lines changed

tools/apput/src/AssemblyStore/AssemblyStore.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Text;
45

56
using Xamarin.Android.Tools;
67

78
namespace ApplicationUtility;
89

910
public class AssemblyStore : IAspect
1011
{
12+
const int MinimumStoreSize = 8;
13+
const uint MagicNumber = 0x41424158; // 'XABA', little-endian
14+
1115
public static string AspectName { get; } = "Assembly Store";
1216

13-
public IDictionary<string, ApplicationAssembly> Assemblies { get; private set; } = null!;
17+
public IDictionary<string, ApplicationAssembly> Assemblies { get; private set; } = new Dictionary<string, ApplicationAssembly> (StringComparer.Ordinal);
1418
public AndroidTargetArch Architecture { get; private set; } = AndroidTargetArch.None;
1519
public ulong NumberOfAssemblies => (ulong)(Assemblies?.Count ?? 0);
1620

@@ -21,6 +25,39 @@ public static IAspect LoadAspect (Stream stream, string? description)
2125

2226
public static bool ProbeAspect (Stream stream, string? description)
2327
{
24-
throw new NotImplementedException ();
28+
// TODO: check if it's an ELF .so and extract the payload, if necessary
29+
30+
// All assembly store files are at least 8 bytes long - space taken up by
31+
// the magic number + store version.
32+
if (stream.Length < MinimumStoreSize) {
33+
Log.Debug ($"AssemblyStore: stream ('{description}') isn't long enough. Need at least {MinimumStoreSize} bytes");
34+
return false;
35+
}
36+
37+
stream.Seek (0, SeekOrigin.Begin);
38+
using var reader = new BinaryReader (stream, Encoding.UTF8, leaveOpen: true);
39+
uint magic = reader.ReadUInt32 ();
40+
if (magic != MagicNumber) {
41+
Log.Debug ($"AssemblyStore: stream ('{description}') doesn't have the correct signature.");
42+
return false;
43+
}
44+
45+
uint version = reader.ReadUInt32 ();
46+
47+
// We currently support version 3. Main store version is kept in the lower 16 bits of the version word
48+
uint mainVersion = version & 0xFFFF;
49+
switch (mainVersion) {
50+
case 3:
51+
return ValidateFormatVersion3 (stream, description);
52+
53+
default:
54+
Log.Debug ($"AssemblyStore: unsupported store version: {mainVersion}");
55+
return false;
56+
}
57+
}
58+
59+
static bool ValidateFormatVersion3 (Stream stream, string? description)
60+
{
61+
return true;
2562
}
2663
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace ApplicationUtility;
2+
3+
// Values correspond to those in `xamarin-app.hh`
4+
enum AssemblyStoreABI
5+
{
6+
Arm64 = 0x00010000,
7+
Arm = 0x00020000,
8+
X86 = 0x00030000,
9+
X64 = 0x00040000,
10+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace ApplicationUtility;
2+
3+
/// <summary>
4+
/// Represents a high-level description of the store hader. It means that this class
5+
/// does **not** correspond to a physical format of the header in the store file. Instead,
6+
/// it contains all the information gathered from the physical file, in a forward compatible
7+
/// way. Forward compatibility means that all public the properties are virtual and nullable,
8+
/// since it's possible that some of them will not be present in the future revisions of the
9+
/// on-disk structure. No public property shall be removed, but any and all of them may be
10+
/// `null` for any given version of the assembly store format. The only exception to this rule
11+
/// is the `Version` property, since it is expected to be present in one way or another in all
12+
/// the future format revisions.
13+
/// </summary>
14+
class AssemblyStoreHeader
15+
{
16+
public AssemblyStoreVersion Version { get; protected set; }
17+
public uint? EntryCount { get; protected set; }
18+
public uint? IndexEntryCount { get; protected set; }
19+
public uint? IndexSize { get; protected set; }
20+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace ApplicationUtility;
2+
3+
class AssemblyStoreVersion
4+
{
5+
public uint MainVersion { get; }
6+
public AssemblyStoreABI ABI { get; }
7+
public bool Is64Bit { get; }
8+
9+
internal AssemblyStoreVersion (uint mainVersion, AssemblyStoreABI abi, bool is64Bit)
10+
{
11+
MainVersion = mainVersion;
12+
ABI = abi;
13+
Is64Bit = is64Bit;
14+
}
15+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace ApplicationUtility;
2+
3+
class Format_V3
4+
{
5+
}

tools/apput/src/Common/Utilities.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.IO;
3+
4+
namespace ApplicationUtility;
5+
6+
class Utilities
7+
{
8+
public static void DeleteFile (string path, bool quiet = true)
9+
{
10+
try {
11+
File.Delete (path);
12+
} catch (Exception ex) {
13+
Log.Debug ($"Failed to delete file '{path}'.", ex);
14+
if (!quiet) {
15+
throw;
16+
}
17+
}
18+
}
19+
20+
public static void CloseAndDeleteFile (FileStream stream, bool quiet = true)
21+
{
22+
string path = stream.Name;
23+
try {
24+
stream.Close ();
25+
} catch (Exception ex) {
26+
Log.Debug ($"Failed to close file stream.", ex);
27+
if (!quiet) {
28+
throw;
29+
}
30+
}
31+
32+
DeleteFile (path);
33+
}
34+
}

tools/apput/src/Package/ApplicationPackage.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,15 @@ void TryLoadAssemblyStores ()
165165
AssemblyStore? TryLoadAssemblyStore (string storePath)
166166
{
167167
// AssemblyStore class owns the stream, don't dispose it here
168-
Stream? storeStream = TryGetEntryStream (storePath);
168+
FileStream? storeStream = TryGetEntryStream (storePath);
169169
if (storeStream == null) {
170170
return null;
171171
}
172172

173173
try {
174174
if (!AssemblyStore.ProbeAspect (storeStream, storePath)) {
175175
Log.Debug ($"Assembly store '{storePath}' is not in a supported format");
176+
storeStream.Close ();
176177
return null;
177178
}
178179

@@ -199,7 +200,7 @@ void TryLoadAndroidManifest ()
199200
string GetNativeLibDir (AndroidTargetArch arch) => $"{NativeLibDirBase}/{MonoAndroidHelper.ArchToAbi (arch)}/";
200201
string GetNativeLibFile (AndroidTargetArch arch, string fileName) => $"{GetNativeLibDir (arch)}{fileName}";
201202

202-
Stream? TryGetEntryStream (string path)
203+
FileStream? TryGetEntryStream (string path)
203204
{
204205
try {
205206
ZipArchiveEntry? entry = Zip.GetEntry (path);
@@ -208,9 +209,16 @@ void TryLoadAndroidManifest ()
208209
return null;
209210
}
210211

211-
return entry.Open ();
212+
string tempFile = Path.GetTempFileName ();
213+
TempFileManager.RegisterFile (tempFile);
214+
215+
Log.Debug ($"Extracting entry '{path}' to '{tempFile}'");
216+
entry.ExtractToFile (tempFile, overwrite: true);
217+
return File.OpenRead (tempFile);
212218
} catch (Exception ex) {
213219
Log.Debug ($"Failed to load entry '{path}' from the archive.", ex);
220+
221+
// TODO: remove temp file (using a helper method, which doesn't exist yet)
214222
return null;
215223
}
216224
}

tools/apput/src/Program.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
using System;
2+
13
namespace ApplicationUtility;
24

35
class Program
46
{
5-
static void Main (string[] args)
6-
{
7-
Log.SetVerbose (true);
8-
IAspect? aspect = Detector.FindAspect (args[0]);
9-
}
7+
static int Main (string[] args)
8+
{
9+
Log.SetVerbose (true);
10+
try {
11+
return Run (args);
12+
} catch (Exception ex) {
13+
Log.ExceptionError ("Unhandled exception", ex);
14+
return 1;
15+
} finally {
16+
TempFileManager.Cleanup ();
17+
}
18+
}
19+
20+
static int Run (string[] args)
21+
{
22+
IAspect? aspect = Detector.FindAspect (args[0]);
23+
return 0;
24+
}
1025
}

0 commit comments

Comments
 (0)