Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ internal static class AndroidEnvironmentInternal
{
internal static Action<Exception>? UnhandledExceptionHandler;

internal static void UnhandledException (Exception e)
public static void UnhandledException (Exception e)
{
if (UnhandledExceptionHandler == null) {
return;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Framework;

namespace Xamarin.Android.Tasks;

public class FixUpMonoAndroidRuntime : AndroidTask
{
public override string TaskPrefix => "FUMAR";

[Required]
public string IntermediateOutputDirectory { get; set; } = String.Empty;

[Required]
public ITaskItem[] ResolvedAssemblies { get; set; } = [];

public override bool RunTask ()
{
List<ITaskItem> monoAndroidRuntimeItems = new ();
foreach (ITaskItem item in ResolvedAssemblies) {

if (!MonoAndroidHelper.StringEquals (Path.GetFileName (item.ItemSpec), "Mono.Android.Runtime.dll", StringComparison.OrdinalIgnoreCase)) {
continue;
}
monoAndroidRuntimeItems.Add (item);
}

if (monoAndroidRuntimeItems.Count == 0) {
Log.LogDebugMessage ("No 'Mono.Android.Runtime.dll' items found");
return !Log.HasLoggedErrors;
}

return MonoAndroidRuntimeMarshalMethodsFixUp.Run (Log, monoAndroidRuntimeItems) && !Log.HasLoggedErrors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,39 +179,13 @@ public void Rewrite (bool brokenExceptionTransitions)
void CopyFile (string source, string target)
{
log.LogDebugMessage ($"[{targetArch}] Copying rewritten assembly: {source} -> {target}");

string targetBackup = $"{target}.bak";
if (File.Exists (target)) {
// Try to avoid sharing violations by first renaming the target
File.Move (target, targetBackup);
}

File.Copy (source, target, true);

if (File.Exists (targetBackup)) {
try {
File.Delete (targetBackup);
} catch (Exception ex) {
// On Windows the deletion may fail, depending on lock state of the original `target` file before the move.
log.LogDebugMessage ($"[{targetArch}] While trying to delete '{targetBackup}', exception was thrown: {ex}");
log.LogDebugMessage ($"[{targetArch}] Failed to delete backup file '{targetBackup}', ignoring.");
}
}
MonoAndroidHelper.CopyFileAvoidSharingViolations (log, source, target);
}

void RemoveFile (string? path)
{
if (String.IsNullOrEmpty (path) || !File.Exists (path)) {
return;
}

try {
log.LogDebugMessage ($"[{targetArch}] Deleting: {path}");
File.Delete (path);
} catch (Exception ex) {
log.LogWarning ($"[{targetArch}] Unable to delete source file '{path}'");
log.LogDebugMessage ($"[{targetArch}] {ex.ToString ()}");
}
log.LogDebugMessage ($"[{targetArch}] Deleting: {path}");
MonoAndroidHelper.TryRemoveFile (log, path);
}

static bool HasUnmanagedCallersOnlyAttribute (MethodDefinition method)
Expand Down Expand Up @@ -504,7 +478,7 @@ MethodDefinition GetUnmanagedCallersOnlyAttributeConstructor (IAssemblyResolver
AssemblyDefinition? asm = resolver.Resolve ("System.Runtime.InteropServices");
if (asm == null)
throw new ArgumentNullException (nameof (asm));

TypeDefinition? unmanagedCallersOnlyAttribute = null;
foreach (ModuleDefinition md in asm.Modules) {
foreach (ExportedType et in md.ExportedTypes) {
Expand Down
35 changes: 35 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -874,5 +874,40 @@ public static void LogTextStreamContents (TaskLoggingHelper log, string message,
log.LogDebugMessage (message);
log.LogDebugMessage (reader.ReadToEnd ());
}

public static void CopyFileAvoidSharingViolations (TaskLoggingHelper log, string source, string dest)
{
string destBackup = $"{dest}.bak";
if (File.Exists (dest)) {
// Try to avoid sharing violations by first renaming the target
File.Move (dest, destBackup);
}

File.Copy (source, dest, true);

if (File.Exists (destBackup)) {
try {
File.Delete (destBackup);
} catch (Exception ex) {
// On Windows the deletion may fail, depending on lock state of the original `target` file before the move.
log.LogDebugMessage ($"While trying to delete '{destBackup}', exception was thrown: {ex}");
log.LogDebugMessage ($"Failed to delete backup file '{destBackup}', ignoring.");
}
}
}

public static void TryRemoveFile (TaskLoggingHelper log, string? filePath)
{
if (String.IsNullOrEmpty (filePath) || !File.Exists (filePath)) {
return;
}

try {
File.Delete (filePath);
} catch (Exception ex) {
log.LogWarning ($"Unable to delete source file '{filePath}'");
log.LogDebugMessage ($"{ex.ToString ()}");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System.Collections.Generic;
using System.IO;
using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Mono.Cecil;

namespace Xamarin.Android.Tasks;

class MonoAndroidRuntimeMarshalMethodsFixUp
{
const string RuntimeTypeName = "Android.Runtime.AndroidEnvironmentInternal";

public static bool Run (TaskLoggingHelper log, List<ITaskItem> items)
{
bool everythingWorked = true;
foreach (ITaskItem item in items) {
if (!ApplyFixUp (log, item)) {
everythingWorked = false;
}
}

return everythingWorked;
}

static bool ApplyFixUp (TaskLoggingHelper log, ITaskItem monoAndroidRuntime)
{
string newDirPath = Path.Combine (Path.GetDirectoryName (monoAndroidRuntime.ItemSpec), "new");
string newFilePath = Path.Combine (newDirPath, Path.GetFileName (monoAndroidRuntime.ItemSpec));
Directory.CreateDirectory (newDirPath);

string origPdbPath = Path.ChangeExtension (monoAndroidRuntime.ItemSpec, ".pdb");
bool havePdb = File.Exists (origPdbPath);

log.LogDebugMessage ($"Fixing up {monoAndroidRuntime.ItemSpec}");
var readerParams = new ReaderParameters () {
InMemory = true,
ReadSymbols = havePdb,
};
AssemblyDefinition asmdef = AssemblyDefinition.ReadAssembly (monoAndroidRuntime.ItemSpec, readerParams);
TypeDefinition? androidRuntimeInternal = null;
foreach (ModuleDefinition module in asmdef.Modules) {
androidRuntimeInternal = FindAndroidRuntimeInternal (module);
if (androidRuntimeInternal != null) {
break;
}
}

if (androidRuntimeInternal == null) {
log.LogDebugMessage ($"'{RuntimeTypeName}' not found in {monoAndroidRuntime.ItemSpec}");
return true; // Not an error, per se...
}
log.LogDebugMessage ($"Found '{RuntimeTypeName}', making it public");
androidRuntimeInternal.IsPublic = true;

var writerParams = new WriterParameters {
WriteSymbols = havePdb,
};
asmdef.Write (newFilePath, writerParams);

CopyFile (log, newFilePath, monoAndroidRuntime.ItemSpec);
RemoveFile (log, newFilePath);

if (!havePdb) {
return true;
}

string pdbPath = Path.ChangeExtension (newFilePath, ".pdb");
havePdb = File.Exists (pdbPath);
if (!havePdb) {
return true;
}

CopyFile (log, pdbPath, origPdbPath);
RemoveFile (log, pdbPath);

return true;
}

static void CopyFile (TaskLoggingHelper log, string source, string target)
{
log.LogDebugMessage ($"Copying rewritten assembly: {source} -> {target}");
MonoAndroidHelper.CopyFileAvoidSharingViolations (log, source, target);
}

static void RemoveFile (TaskLoggingHelper log, string? path)
{
log.LogDebugMessage ($"Deleting: {path}");
MonoAndroidHelper.TryRemoveFile (log, path);
}

static TypeDefinition? FindAndroidRuntimeInternal (ModuleDefinition module)
{
foreach (TypeDefinition t in module.Types) {
if (MonoAndroidHelper.StringEquals (RuntimeTypeName, t.FullName)) {
return t;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<UsingTask TaskName="Xamarin.Android.Tasks.UnzipToFolder" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.GenerateJniRemappingNativeCode" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.PrepareSatelliteAssemblies" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<UsingTask TaskName="Xamarin.Android.Tasks.FixUpMonoAndroidRuntime" AssemblyFile="Xamarin.Android.Build.Tasks.dll" />
<!--
*******************************************
Extensibility hook that allows VS to
Expand Down Expand Up @@ -1605,6 +1606,11 @@ because xbuild doesn't support framework reference assemblies.
EnableNativeRuntimeLinking="$(_AndroidEnableNativeRuntimeLinking)">
</GenerateJavaStubs>

<FixUpMonoAndroidRuntime
Condition=" '$(_AndroidUseMarshalMethods)' == 'true' And '$(AndroidIncludeDebugSymbols)' == 'false' "
IntermediateOutputDirectory="$(IntermediateOutputPath)"
ResolvedAssemblies="@(_ResolvedAssemblies)" />

<RewriteMarshalMethods
Condition=" '$(_AndroidUseMarshalMethods)' == 'true' And '$(AndroidIncludeDebugSymbols)' == 'false' "
EnableManagedMarshalMethodsLookup="$(_AndroidUseManagedMarshalMethodsLookup)"
Expand Down
Loading