diff --git a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
index a4ab68225b0..271b8a73c8d 100644
--- a/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
+++ b/src/Mono.Android/Android.Runtime/AndroidEnvironment.cs
@@ -15,6 +15,8 @@
using Java.Security;
using Javax.Net.Ssl;
+using Microsoft.Android.Runtime;
+
namespace Android.Runtime {
public static class AndroidEnvironment {
@@ -26,6 +28,7 @@ public static class AndroidEnvironment {
static object lock_ = new object ();
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
static Type? httpMessageHandlerType;
+ static bool isFirstGetHttpMessageHandlerCall = true;
static void SetupTrustManager ()
{
@@ -333,66 +336,91 @@ static IWebProxy GetDefaultProxy ()
// This is invoked by
// System.Net.Http.dll!System.Net.Http.HttpClient.cctor
// DO NOT REMOVE
- [DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (Xamarin.Android.Net.AndroidMessageHandler))]
static object GetHttpMessageHandler ()
{
- [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Preserved by the MarkJavaObjects trimmer step.")]
- [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
- static Type TypeGetType (string typeName) =>
- Type.GetType (typeName, throwOnError: false);
-
- if (httpMessageHandlerType is null) {
- var handlerTypeName = Environment.GetEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE")?.Trim ();
- Type? handlerType = null;
- if (!String.IsNullOrEmpty (handlerTypeName))
- handlerType = TypeGetType (handlerTypeName);
-
- // We don't do any type checking or casting here to avoid dependency on System.Net.Http in Mono.Android.dll
- if (handlerType is null || !IsAcceptableHttpMessageHandlerType (handlerType)) {
- handlerType = GetFallbackHttpMessageHandlerType ();
+ lock (lock_) {
+ if (isFirstGetHttpMessageHandlerCall) {
+ isFirstGetHttpMessageHandlerCall = false;
+
+ string? handlerTypeName = Environment.GetEnvironmentVariable ("XA_HTTP_CLIENT_HANDLER_TYPE")?.Trim ();
+ if (RuntimeFeature.XaHttpClientHandlerTypeEnvironmentVariable) {
+ if (!string.IsNullOrEmpty (handlerTypeName)) {
+ Logger.Log (LogLevel.Warn, AndroidLogAppName, $"The $(AndroidHttpClientHandlerType) MSBuild property and the XA_HTTP_CLIENT_HANDLER_TYPE environment variable have been deprecated. If you need to use a custom HTTP handler, consider pass it to the HttpClient via constructor.");
+ }
+
+ httpMessageHandlerType = GetHttpMessageHandlerType (handlerTypeName);
+ } else {
+ if (!string.IsNullOrEmpty (handlerTypeName)) {
+ Logger.Log (LogLevel.Warn, AndroidLogAppName, $"The $(AndroidHttpClientHandlerType) MSBuild property and the XA_HTTP_CLIENT_HANDLER_TYPE environment variable have been deprecated and they will be ignored (value: '{handlerTypeName}'). The default {typeof(Xamarin.Android.Net.AndroidMessageHandler).FullName} handler will be used. If you need to use a custom HTTP handler, pass it to the HttpClient via the constructor.");
+ Logger.Log (LogLevel.Warn, AndroidLogAppName, $"If your codebase relies on the legacy behavior, you can reenable the old behavior by setting the $(AndroidEnableLegacyXaHttpClientHandlerTypeEnvironmentVariable) MSBuild property to 'true' in your project file.");
+ }
+ }
}
+ }
+
+ if (RuntimeFeature.XaHttpClientHandlerTypeEnvironmentVariable) {
+ System.Diagnostics.Debug.Assert(httpMessageHandlerType is not null);
- httpMessageHandlerType = handlerType;
+ return Activator.CreateInstance (httpMessageHandlerType)
+ ?? throw new InvalidOperationException ($"Could not create an instance of HTTP message handler type {httpMessageHandlerType.AssemblyQualifiedName}");
}
- return Activator.CreateInstance (httpMessageHandlerType)
- ?? throw new InvalidOperationException ($"Could not create an instance of HTTP message handler type {httpMessageHandlerType.AssemblyQualifiedName}");
+ return new Xamarin.Android.Net.AndroidMessageHandler ();
}
- static bool IsAcceptableHttpMessageHandlerType (Type handlerType)
+ [RequiresUnreferencedCode ("The handler type might be removed by the trimmer.")]
+ private static Type GetHttpMessageHandlerType (string? handlerTypeName)
{
- if (Extends (handlerType, "System.Net.Http.HttpClientHandler, System.Net.Http")) {
- // It's not possible to construct HttpClientHandler in this method because it would cause infinite recursion
- // as HttpClientHandler's constructor calls the GetHttpMessageHandler function
- Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} cannot be used as the native HTTP handler because it is derived from System.Net.Htt.HttpClientHandler. Use a type that extends System.Net.Http.HttpMessageHandler instead.");
- return false;
+ Type? handlerType = null;
+ if (!String.IsNullOrEmpty (handlerTypeName)) {
+ handlerType = Type.GetType (handlerTypeName);
+
+ if (handlerType is null) {
+ Logger.Log (LogLevel.Warn, AndroidLogAppName, $"The type {handlerTypeName} set as the default HTTP handler was not found. The type was probably linked away.");
+ }
}
- if (!Extends (handlerType, "System.Net.Http.HttpMessageHandler, System.Net.Http")) {
- Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} set as the default HTTP handler is invalid. Use a type that extends System.Net.Http.HttpMessageHandler.");
- return false;
+
+ if (handlerType is null || !IsAcceptableHttpMessageHandlerType (handlerType)) {
+ handlerType = GetFallbackHttpMessageHandlerType ();
}
- return true;
- }
+ return handlerType;
- static bool Extends (
- Type handlerType,
- [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
- string baseTypeName)
- {
- var baseType = Type.GetType (baseTypeName, throwOnError: false);
- return baseType?.IsAssignableFrom (handlerType) ?? false;
- }
+ static bool IsAcceptableHttpMessageHandlerType (Type handlerType)
+ {
+ if (Extends (handlerType, "System.Net.Http.HttpClientHandler, System.Net.Http")) {
+ // It's not possible to construct HttpClientHandler in this method because it would cause infinite recursion
+ // as HttpClientHandler's constructor calls the GetHttpMessageHandler function
+ Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} cannot be used as the native HTTP handler because it is derived from System.Net.Htt.HttpClientHandler. Use a type that extends System.Net.Http.HttpMessageHandler instead.");
+ return false;
+ }
+ if (!Extends (handlerType, "System.Net.Http.HttpMessageHandler, System.Net.Http")) {
+ Logger.Log (LogLevel.Warn, "MonoAndroid", $"The type {handlerType.AssemblyQualifiedName} set as the default HTTP handler is invalid. Use a type that extends System.Net.Http.HttpMessageHandler.");
+ return false;
+ }
- [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
- static Type GetFallbackHttpMessageHandlerType ()
- {
- const string typeName = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android";
- var handlerType = Type.GetType (typeName, throwOnError: false)
- ?? throw new InvalidOperationException ($"The {typeName} was not found. The type was probably linked away.");
+ return true;
+ }
- Logger.Log (LogLevel.Info, "MonoAndroid", $"Using {typeName} as the native HTTP message handler.");
- return handlerType;
+ static bool Extends (
+ Type handlerType,
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+ string baseTypeName)
+ {
+ var baseType = Type.GetType (baseTypeName, throwOnError: false);
+ return baseType?.IsAssignableFrom (handlerType) ?? false;
+ }
+
+ [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+ static Type GetFallbackHttpMessageHandlerType ()
+ {
+ const string typeName = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android";
+ var handlerType = Type.GetType (typeName, throwOnError: false)
+ ?? throw new InvalidOperationException ($"The {typeName} was not found. The type was probably linked away.");
+
+ Logger.Log (LogLevel.Info, "MonoAndroid", $"Using {typeName} as the native HTTP message handler.");
+ return handlerType;
+ }
}
class _Proxy : IWebProxy {
diff --git a/src/Mono.Android/ILLink/ILLink.Substitutions.xml b/src/Mono.Android/ILLink/ILLink.Substitutions.xml
index 239252fe937..9ebb1d8784c 100644
--- a/src/Mono.Android/ILLink/ILLink.Substitutions.xml
+++ b/src/Mono.Android/ILLink/ILLink.Substitutions.xml
@@ -8,5 +8,9 @@
+
+
+
+
diff --git a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
index 814b8c5ab7e..32b7a2ff93d 100644
--- a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
+++ b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
@@ -10,4 +10,9 @@ static class RuntimeFeature
[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}")]
internal static bool ManagedTypeMap { get; } =
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}", out bool isEnabled) ? isEnabled : false;
+
+ [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (XaHttpClientHandlerTypeEnvironmentVariable)}")]
+ [FeatureGuard (typeof (RequiresUnreferencedCodeAttribute))]
+ internal static bool XaHttpClientHandlerTypeEnvironmentVariable { get; } =
+ AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (XaHttpClientHandlerTypeEnvironmentVariable)}", out bool isEnabled) ? isEnabled : false;
}
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
index d2053ce9e21..6e9f076b883 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
@@ -51,6 +51,10 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f
Value="$([MSBuild]::ValueOrDefault('$(_AndroidUseManagedTypeMap)', 'false'))"
Trim="true"
/>
+
0 ? typeName.Substring(0, indexOfComma) : typeName;
- Assert.AreEqual (expectedTypeName, handler.GetType ().FullName);
+ Assert.AreEqual ("Xamarin.Android.Net.AndroidMessageHandler", handler.GetType ().FullName);
}
private static object? GetHttpMessageHandler (string? typeName)
@@ -80,6 +55,8 @@ private static void ClearHttpMessageHandlerTypeCache ()
{
var cacheField = typeof (AndroidEnvironment).GetField ("httpMessageHandlerType", BindingFlags.Static | BindingFlags.NonPublic)!;
cacheField.SetValue (null, null);
+ var isFirstGetHttpMessageHandlerCallField = typeof (AndroidEnvironment).GetField ("isFirstGetHttpMessageHandlerCall", BindingFlags.Static | BindingFlags.NonPublic)!;
+ isFirstGetHttpMessageHandlerCallField.SetValue (null, false);
}
}
}