Skip to content

Commit dd9fbba

Browse files
committed
Mono.Android-Tests might work now
1 parent 6776200 commit dd9fbba

File tree

7 files changed

+75
-7
lines changed

7 files changed

+75
-7
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeRuntime.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Contains code to build and link the native runtime at application build time.
3232
<Output TaskParameter="RequiredLibraries" ItemName="_RequiredLinkLibraries" />
3333
<Output TaskParameter="LinkStartFiles" ItemName="_NativeLinkStartFiles" />
3434
<Output TaskParameter="LinkEndFiles" ItemName="_NativeLinkEndFiles" />
35+
<Output TaskParameter="NativeSymbolsToExport" ItemName="_NativeSymbolsToExport" />
3536
</GetNativeRuntimeComponents>
3637
</Target>
3738

@@ -48,6 +49,7 @@ Contains code to build and link the native runtime at application build time.
4849
NativeObjectFiles="@(_NativeAssemblyTarget)"
4950
NativeLinkStartFiles="@(_NativeLinkStartFiles)"
5051
NativeLinkEndFiles="@(_NativeLinkEndFiles)"
52+
NativeSymbolsToExport="@(_NativeSymbolsToExport)"
5153
LinkLibraries="@(_RequiredLinkLibraries)"
5254
OutputRuntimes="@(_UnifiedNativeRuntime)"
5355
SupportedAbis="@(_BuildTargetAbis)"

src/Xamarin.Android.Build.Tasks/Tasks/GetNativeRuntimeComponents.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,33 @@ public class GetNativeRuntimeComponents : AndroidTask
3232
[Output]
3333
public ITaskItem[] LinkEndFiles { get; set; }
3434

35+
// TODO: more research, for now it seems `--export-dynamic-symbol=name` options generated from
36+
// this array don't work as expected.
37+
[Output]
38+
public ITaskItem[] NativeSymbolsToExport { get; set; }
39+
3540
public override bool RunTask ()
3641
{
3742
var components = new NativeRuntimeComponents (MonoComponents);
3843
var uniqueAbis = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
3944
var archives = new List<ITaskItem> ();
45+
var symbolsToExport = new List<ITaskItem> ();
4046

4147
foreach (NativeRuntimeComponents.Archive archiveItem in components.KnownArchives) {
4248
if (!archiveItem.Include) {
4349
continue;
4450
}
4551
MakeArchiveItem (archiveItem, archives, uniqueAbis);
52+
if (archiveItem.SymbolsToPreserve == null || archiveItem.SymbolsToPreserve.Count == 0) {
53+
continue;
54+
}
55+
56+
foreach (string symbolName in archiveItem.SymbolsToPreserve) {
57+
MakeLibItem (symbolName, symbolsToExport, uniqueAbis);
58+
}
4659
}
4760
NativeArchives = archives.ToArray ();
61+
NativeSymbolsToExport = symbolsToExport.ToArray ();
4862

4963
var items = new List<ITaskItem> ();
5064
foreach (string lib in components.NativeLibraries) {

src/Xamarin.Android.Build.Tasks/Tasks/LinkNativeRuntime.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public class LinkNativeRuntime : AsyncTask
3636
[Required]
3737
public ITaskItem[] NativeLinkEndFiles { get; set; }
3838

39+
[Required]
40+
public ITaskItem[] NativeSymbolsToExport { get; set; }
41+
3942
[Required]
4043
public ITaskItem[] OutputRuntimes { get; set; }
4144

@@ -68,7 +71,8 @@ void LinkRuntime (ITaskItem abiItem)
6871
GetAbiItems (NativeArchives, "_SelectedNativeArchive", abi),
6972
GetAbiItems (LinkLibraries, "_RequiredLinkLibraries", abi),
7073
GetAbiItems (NativeLinkStartFiles, "_NativeLinkStartFiles", abi),
71-
GetAbiItems (NativeLinkEndFiles, "_NativeLinkEndFiles", abi)
74+
GetAbiItems (NativeLinkEndFiles, "_NativeLinkEndFiles", abi),
75+
GetAbiItems (NativeSymbolsToExport, "_NativeSymbolsToExport", abi)
7276
);
7377
}
7478

src/Xamarin.Android.Build.Tasks/Utilities/NativeLinker.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public NativeLinker (TaskLoggingHelper log, string abi, string soname, string bi
100100
}
101101

102102
public bool Link (ITaskItem outputLibraryPath, List<ITaskItem> objectFiles, List<ITaskItem> archives, List<ITaskItem> libraries,
103-
List<ITaskItem> linkStartFiles, List<ITaskItem> linkEndFiles)
103+
List<ITaskItem> linkStartFiles, List<ITaskItem> linkEndFiles, ICollection<ITaskItem>? exportDynamicSymbols = null)
104104
{
105105
log.LogDebugMessage ($"Linking: {outputLibraryPath}");
106106
EnsureCorrectAbi (outputLibraryPath);
@@ -132,6 +132,12 @@ public bool Link (ITaskItem outputLibraryPath, List<ITaskItem> objectFiles, List
132132
WriteFilesToResponseFile (sw, objectFiles);
133133
WriteFilesToResponseFile (sw, archives);
134134

135+
if (exportDynamicSymbols != null && exportDynamicSymbols.Count > 0) {
136+
foreach (ITaskItem symbolItem in exportDynamicSymbols) {
137+
sw.WriteLine ($"--export-dynamic-symbol={symbolItem.ItemSpec}");
138+
}
139+
}
140+
135141
if (excludeExportsLibs.Count > 0) {
136142
string libs = String.Join (",", excludeExportsLibs);
137143
sw.WriteLine ($"--exclude-libs={libs}");

src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal class Archive
1414
public bool Include => shouldInclude (this);
1515
public readonly bool WholeArchive;
1616
public bool DontExportSymbols { get; set; }
17+
public HashSet<string>? SymbolsToPreserve { get; set; }
1718

1819
Func<Archive, bool> shouldInclude;
1920

@@ -89,7 +90,23 @@ public NativeRuntimeComponents (ITaskItem[] monoComponents)
8990
new BclArchive ("libSystem.Globalization.Native.a"),
9091
new BclArchive ("libSystem.IO.Compression.Native.a"),
9192
new BclArchive ("libSystem.Native.a"),
92-
new BclArchive ("libSystem.Security.Cryptography.Native.Android.a", jniOnLoadName: "AndroidCryptoNative_InitLibraryOnLoad"),
93+
new BclArchive ("libSystem.Security.Cryptography.Native.Android.a", jniOnLoadName: "AndroidCryptoNative_InitLibraryOnLoad") {
94+
SymbolsToPreserve = new (StringComparer.Ordinal) {
95+
// This isn't referenced directly by any code in libSystem.Security.Cryptography.Native.Android. It is instead
96+
// referenced by the Java code shipped with the component (`DotnetProxyTrustManager`), as a native Java method:
97+
//
98+
// static native boolean verifyRemoteCertificate(long sslStreamProxyHandle);
99+
//
100+
// Therefore we must reference it explicitly
101+
"Java_net_dot_android_crypto_DotnetProxyTrustManager_verifyRemoteCertificate"
102+
},
103+
104+
// For now, we have to export all the symbols from this archive because we need the above `Java_net*` symbol to be
105+
// externally visible, and the linker's `--exclude-libs` flag works on the archive (.a) level.
106+
//
107+
// TODO: use `llvm-ar` to extract the relevant object file and link it separately?
108+
DontExportSymbols = false,
109+
},
93110

94111
// .NET for Android
95112
new AndroidArchive ("libpinvoke-override-dynamic-release.a"),

src/Xamarin.Android.Build.Tasks/Utilities/PreservePinvokesNativeAssemblyGenerator.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ protected override void Construct (LlvmIrModule module)
102102
Log.LogDebugMessage (" Looking for enabled native components");
103103
var componentNames = new HashSet<string> (StringComparer.Ordinal);
104104
var jniOnLoadNames = new HashSet<string> (StringComparer.Ordinal);
105+
var symbolsToExplicitlyPreserve = new HashSet<LlvmIrGlobalVariableReference> ();
105106
var nativeComponents = new NativeRuntimeComponents (monoComponents);
106107
foreach (NativeRuntimeComponents.Archive archiveItem in nativeComponents.KnownArchives) {
107108
if (!archiveItem.Include) {
@@ -113,6 +114,15 @@ protected override void Construct (LlvmIrModule module)
113114
if (!String.IsNullOrEmpty (archiveItem.JniOnLoadName)) {
114115
jniOnLoadNames.Add (archiveItem.JniOnLoadName);
115116
}
117+
118+
if (archiveItem.SymbolsToPreserve == null || archiveItem.SymbolsToPreserve.Count == 0) {
119+
continue;
120+
}
121+
122+
foreach (string symbolName in archiveItem.SymbolsToPreserve) {
123+
symbolsToExplicitlyPreserve.Add (new LlvmIrGlobalVariableReference (symbolName));
124+
DeclareDummyFunction (module, symbolName);
125+
}
116126
}
117127

118128
if (componentNames.Count == 0) {
@@ -124,13 +134,11 @@ protected override void Construct (LlvmIrModule module)
124134
var jniOnLoadPointers = new List<LlvmIrVariableReference> ();
125135
foreach (string name in jniOnLoadNames) {
126136
jniOnLoadPointers.Add (new LlvmIrGlobalVariableReference (name));
127-
128-
// Just a dummy declaration, we don't care about the arguments
129-
var funcSig = new LlvmIrFunctionSignature (name, returnType: typeof(void));
130-
var _ = module.DeclareExternalFunction (funcSig);
137+
DeclareDummyFunction (module, name);
131138
}
132139
module.AddGlobalVariable ("__jni_on_load_handlers", jniOnLoadPointers, LlvmIrVariableOptions.GlobalConstant);
133140
module.AddGlobalVariable ("__jni_on_load_handler_names", jniOnLoadNames, LlvmIrVariableOptions.GlobalConstant);
141+
module.AddGlobalVariable ("__explicitly_preserved_symbols", symbolsToExplicitlyPreserve, LlvmIrVariableOptions.GlobalConstant);
134142

135143
bool is64Bit = state.TargetArch switch {
136144
AndroidTargetArch.Arm64 => true,
@@ -360,4 +368,11 @@ bool Matches (string libraryName, string componentName)
360368
return String.Compare (libraryName, componentName, StringComparison.Ordinal) == 0;
361369
}
362370
}
371+
372+
static void DeclareDummyFunction (LlvmIrModule module, string name)
373+
{
374+
// Just a dummy declaration, we don't care about the arguments
375+
var funcSig = new LlvmIrFunctionSignature (name, returnType: typeof(void));
376+
var _ = module.DeclareExternalFunction (funcSig);
377+
}
363378
}

src/native/pinvoke-override/dynamic.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern "C" {
1818
extern const uint32_t __jni_on_load_handler_count;
1919
extern const JniOnLoadHandler __jni_on_load_handlers[];
2020
extern const char* __jni_on_load_handler_names[];
21+
extern const void* __explicitly_preserved_symbols[];
2122
}
2223

2324
[[gnu::flatten]]
@@ -72,4 +73,13 @@ void PinvokeOverride::handle_jni_on_load (JavaVM *vm, void *reserved) noexcept
7273
for (uint32_t i = 0; i < __jni_on_load_handler_count; i++) {
7374
__jni_on_load_handlers[i] (vm, reserved);
7475
}
76+
77+
// This is just to reference the generated array, all we need from it is to be there
78+
// TODO: see if there's an attribute we can use to make the linker keep the symbol instead.
79+
// void *first_ptr = __explicitly_preserved_symbols;
80+
// if (first_ptr == nullptr) {
81+
// // This will never actually be logged, since by the time this function is called we haven't initialized
82+
// // logging categories yet. It's here just to have some code in the if statement body.
83+
// log_debug (LOG_ASSEMBLY, "No explicitly preserved symbols");
84+
// }
7585
}

0 commit comments

Comments
 (0)