Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move DSO wrapping code to BuildApk #9349

Merged
merged 8 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build-tools/create-packs/Microsoft.Android.Runtime.proj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ projects that use the Microsoft.Android framework in .NET 6+.
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libmono-android.release.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-debug-app-helper.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libxamarin-native-tracing.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libarchive-dso-stub.so" />
<_AndroidRuntimePackAssets Include="$(MicrosoftAndroidSdkOutDir)lib\$(AndroidRID)\libunwind_xamarin.a" />
<FrameworkListFileClass Include="@(_AndroidRuntimePackAssemblies->'%(Filename)%(Extension)')" Profile="Android" />
<FrameworkListFileClass Include="@(_AndroidRuntimePackAssets->'%(Filename)%(Extension)')" Profile="Android" />
Expand Down
4 changes: 4 additions & 0 deletions build-tools/installers/create-installers.targets
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libm.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libm.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm64\libarchive-dso-stub.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-arm\libarchive-dso-stub.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x64\libarchive-dso-stub.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)dsostubs\android-x86\libarchive-dso-stub.so" />
</ItemGroup>
<ItemGroup>
<_MSBuildTargetsSrcFiles Include="$(MSBuildTargetsSrcDir)\Xamarin.Android.AvailableItems.targets" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ _ResolveAssemblies MSBuild target.
<UsingTask TaskName="Xamarin.Android.Tasks.ProcessAssemblies" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.ProcessNativeLibraries" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.StripNativeLibraries" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />
<UsingTask TaskName="Xamarin.Android.Tasks.PrepareDSOWrapperState" AssemblyFile="$(_XamarinAndroidBuildTasksAssembly)" />

<!-- HACK: workaround for: https://github.com/dotnet/sdk/issues/25679 -->
<Target Name="_RemoveLinuxFrameworkReferences"
Expand Down Expand Up @@ -124,16 +123,9 @@ _ResolveAssemblies MSBuild target.
</ItemGroup>

<ItemGroup>
<_ResolvedArchiveDSOStub Include="@(ResolvedFileToPublish)" Condition=" '%(ResolvedFileToPublish.Filename)%(ResolvedFileToPublish.Extension)' == 'libarchive-dso-stub.so' " />
<ResolvedFileToPublish Remove="@(_ResolvedArchiveDSOStub)" />
grendello marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>

<!-- This must run as early as possible, as soon as we have locations of the .so files and before any wrapping/packaging is done -->
<PrepareDSOWrapperState
ArchiveDSOStubs="@(_ResolvedArchiveDSOStub)"
AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)"
BaseOutputDirectory="$(IntermediateOutputPath)" />

<!-- All assemblies must be per-RID, thus no `->Distinct()` on `InputAssemblies` or `ResolvedSymbols` items -->
<ProcessAssemblies
RuntimeIdentifiers="@(_RIDs)"
Expand Down
48 changes: 24 additions & 24 deletions src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ public class BuildApk : AndroidTask

public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit;

[Required]
public string AndroidBinUtilsDirectory { get; set; }

[Required]
public string IntermediateOutputPath { get; set; }

[Required]
public string ProjectFullPath { get; set; }

Expand Down Expand Up @@ -141,7 +147,7 @@ protected virtual void FixupArchive (ZipArchiveEx zip) { }

List<Regex> includePatterns = new List<Regex> ();

void ExecuteWithAbi (string [] supportedAbis, string apkInputPath, string apkOutputPath, bool debug, bool compress, IDictionary<AndroidTargetArch, Dictionary<string, CompressedAssemblyInfo>> compressedAssembliesInfo, string assemblyStoreApkName)
void ExecuteWithAbi (DSOWrapperGenerator.Config dsoWrapperConfig, string [] supportedAbis, string apkInputPath, string apkOutputPath, bool debug, bool compress, IDictionary<AndroidTargetArch, Dictionary<string, CompressedAssemblyInfo>> compressedAssembliesInfo, string assemblyStoreApkName)
{
ArchiveFileList files = new ArchiveFileList ();
bool refresh = true;
Expand Down Expand Up @@ -208,11 +214,11 @@ void ExecuteWithAbi (string [] supportedAbis, string apkInputPath, string apkOut
}

if (EmbedAssemblies) {
AddAssemblies (apk, debug, compress, compressedAssembliesInfo, assemblyStoreApkName);
AddAssemblies (dsoWrapperConfig, apk, debug, compress, compressedAssembliesInfo, assemblyStoreApkName);
apk.Flush ();
}

AddRuntimeConfigBlob (apk);
AddRuntimeConfigBlob (dsoWrapperConfig, apk);
AddRuntimeLibraries (apk, supportedAbis);
apk.Flush();
AddNativeLibraries (files, supportedAbis);
Expand Down Expand Up @@ -354,14 +360,17 @@ public override bool RunTask ()
throw new InvalidOperationException ($"Assembly compression info not found for key '{key}'. Compression will not be performed.");
}

ExecuteWithAbi (SupportedAbis, ApkInputPath, ApkOutputPath, debug, compress, compressedAssembliesInfo, assemblyStoreApkName: null);
DSOWrapperGenerator.Config dsoWrapperConfig = DSOWrapperGenerator.GetConfig (Log, AndroidBinUtilsDirectory, IntermediateOutputPath);
ExecuteWithAbi (dsoWrapperConfig, SupportedAbis, ApkInputPath, ApkOutputPath, debug, compress, compressedAssembliesInfo, assemblyStoreApkName: null);
outputFiles.Add (ApkOutputPath);
if (CreatePackagePerAbi && SupportedAbis.Length > 1) {
var abiArray = new string[] { String.Empty };
foreach (var abi in SupportedAbis) {
existingEntries.Clear ();
var path = Path.GetDirectoryName (ApkOutputPath);
var apk = Path.GetFileNameWithoutExtension (ApkOutputPath);
ExecuteWithAbi (new [] { abi }, String.Format ("{0}-{1}", ApkInputPath, abi),
abiArray[0] = abi;
ExecuteWithAbi (dsoWrapperConfig, abiArray, String.Format ("{0}-{1}", ApkInputPath, abi),
Path.Combine (path, String.Format ("{0}-{1}.apk", apk, abi)),
debug, compress, compressedAssembliesInfo, assemblyStoreApkName: abi);
outputFiles.Add (Path.Combine (path, String.Format ("{0}-{1}.apk", apk, abi)));
Expand All @@ -371,20 +380,11 @@ public override bool RunTask ()
OutputFiles = outputFiles.Select (a => new TaskItem (a)).ToArray ();

Log.LogDebugTaskItems (" [Output] OutputFiles :", OutputFiles);
DSOWrapperGenerator.CleanUp (this);
DSOWrapperGenerator.CleanUp (dsoWrapperConfig);

return !Log.HasLoggedErrors;
}

internal DSOWrapperGenerator.Config EnsureConfig ()
{
var config = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal<DSOWrapperGenerator.Config> (ProjectSpecificTaskObjectKey (DSOWrapperGenerator.RegisteredConfigKey), RegisteredTaskObjectLifetime.Build);
if (config is null) {
throw new InvalidOperationException ("Internal error: no registered config found");
}
return config;
}

static Regex FileGlobToRegEx (string fileGlob, RegexOptions options)
{
StringBuilder sb = new StringBuilder ();
Expand All @@ -403,7 +403,7 @@ static Regex FileGlobToRegEx (string fileGlob, RegexOptions options)
return new Regex (sb.ToString (), options);
}

void AddRuntimeConfigBlob (ZipArchiveEx apk)
void AddRuntimeConfigBlob (DSOWrapperGenerator.Config dsoWrapperConfig, ZipArchiveEx apk)
{
// We will place rc.bin in the `lib` directory next to the blob, to make startup slightly faster, as we will find the config file right after we encounter
// our assembly store. Not only that, but also we'll be able to skip scanning the `base.apk` archive when split configs are enabled (which they are in 99%
Expand All @@ -414,13 +414,13 @@ void AddRuntimeConfigBlob (ZipArchiveEx apk)
// Prefix it with `a` because bundletool sorts entries alphabetically, and this will place it right next to `assemblies.*.blob.so`, which is what we
// like since we can finish scanning the zip central directory earlier at startup.
string inArchivePath = MakeArchiveLibPath (abi, "libarc.bin.so");
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (MonoAndroidHelper.AbiToTargetArch (abi), RuntimeConfigBinFilePath, Path.GetFileName (inArchivePath), this);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, MonoAndroidHelper.AbiToTargetArch (abi), RuntimeConfigBinFilePath, Path.GetFileName (inArchivePath));
AddFileToArchiveIfNewer (apk, wrappedSourcePath, inArchivePath, compressionMethod: GetCompressionMethod (inArchivePath));
}
}
}

void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<AndroidTargetArch, Dictionary<string, CompressedAssemblyInfo>> compressedAssembliesInfo, string assemblyStoreApkName)
void AddAssemblies (DSOWrapperGenerator.Config dsoWrapperConfig, ZipArchiveEx apk, bool debug, bool compress, IDictionary<AndroidTargetArch, Dictionary<string, CompressedAssemblyInfo>> compressedAssembliesInfo, string assemblyStoreApkName)
{
string sourcePath;
AssemblyCompression.AssemblyData compressedAssembly = null;
Expand Down Expand Up @@ -455,7 +455,7 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And
foreach (var kvp in assemblyStorePaths) {
string abi = MonoAndroidHelper.ArchToAbi (kvp.Key);
inArchivePath = MakeArchiveLibPath (abi, "lib" + Path.GetFileName (kvp.Value));
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (kvp.Key, kvp.Value, Path.GetFileName (inArchivePath), this);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, kvp.Key, kvp.Value, Path.GetFileName (inArchivePath));
AddFileToArchiveIfNewer (apk, wrappedSourcePath, inArchivePath, GetCompressionMethod (inArchivePath));
}

Expand All @@ -474,12 +474,12 @@ void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch

// Add assembly
(string assemblyPath, string assemblyDirectory) = GetInArchiveAssemblyPath (assembly);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (arch, sourcePath, Path.GetFileName (assemblyPath), this);
string wrappedSourcePath = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, arch, sourcePath, Path.GetFileName (assemblyPath));
AddFileToArchiveIfNewer (apk, wrappedSourcePath, assemblyPath, compressionMethod: GetCompressionMethod (assemblyPath));

// Try to add config if exists
var config = Path.ChangeExtension (assembly.ItemSpec, "dll.config");
AddAssemblyConfigEntry (apk, arch, assemblyDirectory, config);
AddAssemblyConfigEntry (dsoWrapperConfig, apk, arch, assemblyDirectory, config);

// Try to add symbols if Debug
if (!debug) {
Expand All @@ -492,7 +492,7 @@ void DoAddAssembliesFromArchCollection (TaskLoggingHelper log, AndroidTargetArch
}

string archiveSymbolsPath = assemblyDirectory + MonoAndroidHelper.MakeDiscreteAssembliesEntryName (Path.GetFileName (symbols));
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (arch, symbols, Path.GetFileName (archiveSymbolsPath), this);
string wrappedSymbolsPath = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, arch, symbols, Path.GetFileName (archiveSymbolsPath));
AddFileToArchiveIfNewer (
apk,
wrappedSymbolsPath,
Expand Down Expand Up @@ -531,7 +531,7 @@ bool AddFileToArchiveIfNewer (ZipArchiveEx apk, string file, string inArchivePat
return true;
}

void AddAssemblyConfigEntry (ZipArchiveEx apk, AndroidTargetArch arch, string assemblyPath, string configFile)
void AddAssemblyConfigEntry (DSOWrapperGenerator.Config dsoWrapperConfig, ZipArchiveEx apk, AndroidTargetArch arch, string assemblyPath, string configFile)
{
string inArchivePath = MonoAndroidHelper.MakeDiscreteAssembliesEntryName (assemblyPath + Path.GetFileName (configFile));
existingEntries.Remove (inArchivePath);
Expand All @@ -547,7 +547,7 @@ void AddAssemblyConfigEntry (ZipArchiveEx apk, AndroidTargetArch arch, string as
}

Log.LogDebugMessage ($"Adding {configFile} as the archive file is out of date.");
string wrappedConfigFile = DSOWrapperGenerator.WrapIt (arch, configFile, Path.GetFileName (inArchivePath), this);
string wrappedConfigFile = DSOWrapperGenerator.WrapIt (Log, dsoWrapperConfig, arch, configFile, Path.GetFileName (inArchivePath));
apk.AddFileAndFlush (wrappedConfigFile, inArchivePath, compressionMethod);
}

Expand Down
54 changes: 0 additions & 54 deletions src/Xamarin.Android.Build.Tasks/Tasks/PrepareDSOWrapperState.cs

This file was deleted.

40 changes: 30 additions & 10 deletions src/Xamarin.Android.Build.Tasks/Utilities/DSOWrapperGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ class DSOWrapperGenerator

internal class Config
{
public Dictionary<AndroidTargetArch, ITaskItem> DSOStubPaths { get; }
public Dictionary<AndroidTargetArch, string> DSOStubPaths { get; }
public string AndroidBinUtilsDirectory { get; }
public string BaseOutputDirectory { get; }

public Config (Dictionary<AndroidTargetArch, ITaskItem> stubPaths, string androidBinUtilsDirectory, string baseOutputDirectory)
public Config (Dictionary<AndroidTargetArch, string> stubPaths, string androidBinUtilsDirectory, string baseOutputDirectory)
{
DSOStubPaths = stubPaths;
AndroidBinUtilsDirectory = androidBinUtilsDirectory;
Expand All @@ -53,6 +53,30 @@ public Config (Dictionary<AndroidTargetArch, ITaskItem> stubPaths, string androi
//
const ulong PayloadSectionAlignment = 0x4000;

public static Config GetConfig (TaskLoggingHelper log, string androidBinUtilsDirectory, string baseOutputDirectory)
{
var stubPaths = new Dictionary<AndroidTargetArch, string> ();
string archiveDSOStubsRootDir = MonoAndroidHelper.GetDSOStubsRootDirectoryPath (androidBinUtilsDirectory);

foreach (string dir in Directory.EnumerateDirectories (archiveDSOStubsRootDir, "android-*")) {
string rid = Path.GetFileName (dir);
AndroidTargetArch arch = MonoAndroidHelper.RidToArchMaybe (rid);
if (arch == AndroidTargetArch.None) {
log.LogDebugMessage ($"Unable to extract a supported RID name from directory path '{dir}'");
continue;
}

string stubPath = Path.Combine (dir, "libarchive-dso-stub.so");
if (!File.Exists (stubPath)) {
throw new InvalidOperationException ($"Internal error: archive DSO stub file '{stubPath}' does not exist");
}

stubPaths.Add (arch, stubPath);
}

return new Config (stubPaths, androidBinUtilsDirectory, baseOutputDirectory);
}

static string GetArchOutputPath (AndroidTargetArch targetArch, Config config)
{
return Path.Combine (config.BaseOutputDirectory, MonoAndroidHelper.ArchToRid (targetArch), "wrapped");
Expand All @@ -62,22 +86,20 @@ static string GetArchOutputPath (AndroidTargetArch targetArch, Config config)
/// Puts the indicated file (<paramref name="payloadFilePath"/>) inside an ELF shared library and returns
/// path to the wrapped file.
/// </summary>
public static string WrapIt (AndroidTargetArch targetArch, string payloadFilePath, string outputFileName, BuildApk task)
public static string WrapIt (TaskLoggingHelper log, Config config, AndroidTargetArch targetArch, string payloadFilePath, string outputFileName)
{
TaskLoggingHelper log = task.Log;
log.LogDebugMessage ($"[{targetArch}] Putting '{payloadFilePath}' inside ELF shared library '{outputFileName}'");
Config config = task.EnsureConfig ();
string outputDir = GetArchOutputPath (targetArch, config);
Directory.CreateDirectory (outputDir);

string outputFile = Path.Combine (outputDir, outputFileName);
log.LogDebugMessage ($" output file path: {outputFile}");

if (!config.DSOStubPaths.TryGetValue (targetArch, out ITaskItem? stubItem)) {
if (!config.DSOStubPaths.TryGetValue (targetArch, out string? stubPath)) {
throw new InvalidOperationException ($"Internal error: archive DSO stub location not known for architecture '{targetArch}'");
}

File.Copy (stubItem.ItemSpec, outputFile, overwrite: true);
File.Copy (stubPath, outputFile, overwrite: true);

string quotedOutputFile = MonoAndroidHelper.QuoteFileNameArgument (outputFile);
string objcopy = Path.Combine (config.AndroidBinUtilsDirectory, MonoAndroidHelper.GetExecutablePath (config.AndroidBinUtilsDirectory, "llvm-objcopy"));
Expand Down Expand Up @@ -107,10 +129,8 @@ public static string WrapIt (AndroidTargetArch targetArch, string payloadFilePat
/// created by this class. The reason to do so is to ensure that we don't package any "stale" content and those
/// wrapper files aren't part of any dependency chain so it's hard to check their up to date state.
/// </summary>
public static void CleanUp (BuildApk task)
public static void CleanUp (Config config)
{
Config config = task.EnsureConfig();

foreach (var kvp in config.DSOStubPaths) {
string outputDir = GetArchOutputPath (kvp.Key, config);
if (!Directory.Exists (outputDir)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,19 @@ public static string RidToAbi (string rid)
return abi;
}

public static AndroidTargetArch RidToArch (string rid)
public static AndroidTargetArch RidToArchMaybe (string rid)
{
if (!RidToArchMap.TryGetValue (rid, out AndroidTargetArch arch)) {
return AndroidTargetArch.None;
};

return arch;
}

public static AndroidTargetArch RidToArch (string rid)
{
AndroidTargetArch arch = RidToArchMaybe (rid);
if (arch == AndroidTargetArch.None) {
throw new NotSupportedException ($"Internal error: unsupported Runtime Identifier '{rid}'");
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,12 @@ public static string GetLibstubsRootDirectoryPath (string androidBinUtilsDirecto
return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "libstubs"));
}

public static string GetDSOStubsRootDirectoryPath (string androidBinUtilsDirectory)
{
string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory);
return Path.GetFullPath (Path.Combine (androidBinUtilsDirectory, relPath, "dsostubs"));
}

public static string GetNativeLibsRootDirectoryPath (string androidBinUtilsDirectory)
{
string relPath = GetToolsRootDirectoryRelativePath (androidBinUtilsDirectory);
Expand Down
Loading