Skip to content

Commit 30ebb25

Browse files
mcummingAgnik7dustin-wojciechowskidalexsoto
authored
Use feature flags for CFNetworkHandler and NSUrlSessionHandler (#22703)
Continuation of #19003 This means the linker will remove either `CFNetworkHandler` or `NSUrlSessionHandler` depending on which is chosen at build time (or both, if neither is chosen). This will shrink app size a little bit, here are the types and members that are no longer included when using `NSUrlSessionHandler`: https://gist.github.com/rolfbjarne/102d77d5f105a7c98ac6be19de725dd5 A very basic app is ~55kb / 0.2% smaller: https://gist.github.com/rolfbjarne/a1cb6898aa560f0a891286be20b9bc3e Fixes #14298. --------- Co-authored-by: Agnik Bakshi <[email protected]> Co-authored-by: Dustin Wojciechowski <[email protected]> Co-authored-by: Michael Cummings <[email protected]> Co-authored-by: Alex Soto <[email protected]>
1 parent 9133afe commit 30ebb25

26 files changed

+180
-191
lines changed

dotnet/targets/Xamarin.Shared.Sdk.targets

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,12 @@
560560
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' == 'NativeAOT'">true</_IsNativeAOTFeature>
561561
<_IsNativeAOTFeature Condition="'$(_XamarinRuntime)' != 'NativeAOT'">false</_IsNativeAOTFeature>
562562

563+
<!-- Set CFNetworkHandler and NSUrlSessionHandler values -->
564+
<_IsCFNetworkHandlerFeature Condition="'$(UseNativeHttpHandler)' == 'true' And '$(MtouchHttpClientHandler)' == 'CFNetworkHandler'">true</_IsCFNetworkHandlerFeature>
565+
<_IsCFNetworkHandlerFeature Condition="'$(_IsCFNetworkHandlerFeature)' == ''">false</_IsCFNetworkHandlerFeature>
566+
<_IsNSUrlSessionHandlerFeature Condition="'$(UseNativeHttpHandler)' == 'true' And '$(MtouchHttpClientHandler)' == 'NSUrlSessionHandler'">true</_IsNSUrlSessionHandlerFeature>
567+
<_IsNSUrlSessionHandlerFeature Condition="'$(_IsNSUrlSessionHandlerFeature)' == ''">false</_IsNSUrlSessionHandlerFeature>
568+
563569
<!-- Set default ValidateObjectPointers value -->
564570
<_ValidateObjectPointers Condition="'$(_ValidateObjectPointers)' == ''">false</_ValidateObjectPointers>
565571

@@ -678,6 +684,10 @@
678684
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsNativeAOT" Value="$(_IsNativeAOTFeature)" Trim="true" />
679685
<RuntimeHostConfigurationOption Include="ObjCRuntime.Class.ValidateObjectPointers" Value="$(_ValidateObjectPointers)" Trim="true" />
680686

687+
<!-- Configure System.Net.Http Native Handlers -->
688+
<RuntimeHostConfigurationOption Include="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" Value="$(_IsNSUrlSessionHandlerFeature)" Trim="true" />
689+
<RuntimeHostConfigurationOption Include="System.Net.Http.NativeHandler.UseCFNetworkHandler" Value="$(_IsCFNetworkHandlerFeature)" Trim="true" />
690+
681691
<!-- Mark all assemblies to be copied if we're not linking any assemblies -->
682692
<ResolvedFileToPublish
683693
Update="@(ResolvedFileToPublish)"

src/ILLink.Substitutions.MacCatalyst.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
<method signature="System.Boolean get_IsNativeAOT()" body="stub" feature="ObjCRuntime.Runtime.IsNativeAOT" featurevalue="true" value="true" />
1111
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
1212
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
13+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
14+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
15+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
16+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="true" value="true" />
1317
</type>
1418
<type fullname="ObjCRuntime.Class">
1519
<method signature="System.Boolean get_ValidateObjectPointers()" body="stub" feature="ObjCRuntime.Class.ValidateObjectPointers" featurevalue="false" value="false" />

src/ILLink.Substitutions.ios.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
<method signature="System.Int32 GetRuntimeArch()" body="stub" feature="ObjCRuntime.Runtime.Arch.IsSimulator" featurevalue="true" value="1" />
1313
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
1414
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
15+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
16+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
17+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
18+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="true" value="true" />
1519
</type>
1620
<type fullname="ObjCRuntime.Class">
1721
<method signature="System.Boolean get_ValidateObjectPointers()" body="stub" feature="ObjCRuntime.Class.ValidateObjectPointers" featurevalue="false" value="false" />

src/ILLink.Substitutions.macOS.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
<method signature="System.Boolean get_IsNativeAOT()" body="stub" feature="ObjCRuntime.Runtime.IsNativeAOT" featurevalue="true" value="true" />
1010
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
1111
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
12+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
13+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
14+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
15+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="true" value="true" />
1216
</type>
1317
<type fullname="ObjCRuntime.Class">
1418
<method signature="System.Boolean get_ValidateObjectPointers()" body="stub" feature="ObjCRuntime.Class.ValidateObjectPointers" featurevalue="false" value="false" />

src/ILLink.Substitutions.tvos.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
<method signature="System.Int32 GetRuntimeArch()" body="stub" feature="ObjCRuntime.Runtime.Arch.IsSimulator" featurevalue="true" value="1" />
1313
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="false" value="false" />
1414
<method signature="System.Boolean get_IsManagedStaticRegistrar()" body="stub" feature="ObjCRuntime.Runtime.IsManagedStaticRegistrar" featurevalue="true" value="true" />
15+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="false" value="false" />
16+
<method signature="System.Boolean get_UseCFNetworkHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseCFNetworkHandler" featurevalue="true" value="true" />
17+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="false" value="false" />
18+
<method signature="System.Boolean get_UseNSUrlSessionHandler()" body="stub" feature="System.Net.Http.NativeHandler.UseNSUrlSessionHandler" featurevalue="true" value="true" />
1519
</type>
1620
<type fullname="ObjCRuntime.Class">
1721
<method signature="System.Boolean get_ValidateObjectPointers()" body="stub" feature="ObjCRuntime.Class.ValidateObjectPointers" featurevalue="false" value="false" />

src/ObjCRuntime/Runtime.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,14 @@ public static bool DynamicRegistrationSupported {
285285
}
286286
}
287287

288+
// The linker may turn calls to this property into a constant
289+
[BindingImpl (BindingImplOptions.Optimizable)]
290+
internal static bool UseNSUrlSessionHandler => AppContext.TryGetSwitch ("System.Net.Http.NativeHandler.UseNSUrlSessionHandler", out bool isDefault) ? isDefault : true;
291+
292+
// The linker may turn calls to this property into a constant
293+
[BindingImpl (BindingImplOptions.Optimizable)]
294+
internal static bool UseCFNetworkHandler => AppContext.TryGetSwitch ("System.Net.Http.NativeHandler.UseCFNetworkHandler", out bool isDefault) ? isDefault : false;
295+
288296
internal static bool Initialized {
289297
get { return initialized; }
290298
}

src/ObjCRuntime/RuntimeOptions.cs

Lines changed: 5 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -2,202 +2,30 @@
22
using System.IO;
33
using System.Text;
44

5-
#if MTOUCH || MMP || BUNDLER
6-
using Mono.Cecil;
7-
using Xamarin.Linker;
8-
#else
95
using System.Net.Http;
106
using Foundation;
117
using ObjCRuntime;
12-
#endif
138

149
#nullable enable
1510

16-
#if MMP || MMP_TEST || MTOUCH || BUNDLER
17-
namespace Xamarin.Bundler {
18-
#else
1911
namespace ObjCRuntime {
20-
#endif
2112
class RuntimeOptions {
22-
#if !LEGACY_TOOLS
2313
const string SocketsHandlerValue = "SocketsHttpHandler";
24-
#else
25-
const string HttpClientHandlerValue = "HttpClientHandler";
26-
#endif
2714
const string CFNetworkHandlerValue = "CFNetworkHandler";
2815
const string NSUrlSessionHandlerValue = "NSUrlSessionHandler";
2916

30-
string? http_message_handler;
31-
32-
#if MTOUCH || MMP || BUNDLER
33-
/*
34-
* This section is only used by the tools
35-
*/
36-
internal static RuntimeOptions Create (Application app, string? http_message_handler, string? tls_provider)
37-
{
38-
var options = new RuntimeOptions ();
39-
options.http_message_handler = ParseHttpMessageHandler (app, http_message_handler);
40-
return options;
41-
}
42-
43-
static string ParseHttpMessageHandler (Application app, string? value)
44-
{
45-
switch (value) {
46-
// default
47-
case null:
48-
#if !LEGACY_TOOLS
49-
return NSUrlSessionHandlerValue;
50-
#else
51-
return HttpClientHandlerValue;
52-
#endif
53-
case CFNetworkHandlerValue:
54-
#if !LEGACY_TOOLS
55-
case SocketsHandlerValue:
56-
#else
57-
case HttpClientHandlerValue:
58-
#endif
59-
return value;
60-
case NSUrlSessionHandlerValue:
61-
return value;
62-
default:
63-
throw ErrorHelper.CreateError (2010, Errors.MT2010, value);
64-
}
65-
}
66-
67-
internal void Write (string app_dir)
68-
{
69-
// note: we always create the file because the simulator won't remove old files
70-
// that might become useful if we add new options in the future
71-
var content = new StringBuilder ();
72-
content.AppendLine ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
73-
content.AppendLine ("<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">");
74-
content.AppendLine ("<plist version=\\\"1.0\\\">");
75-
content.AppendLine ("<dict>");
76-
content.AppendLine ("<key>HttpMessageHandler</key>");
77-
content.Append ("<string>");
78-
content.Append (http_message_handler);
79-
content.AppendLine ("</string>");
80-
content.AppendLine ("</dict>");
81-
content.AppendLine ("</plist>");
82-
83-
var file_name = GetFileName (app_dir);
84-
Xamarin.Bundler.Driver.WriteIfDifferent (file_name, content.ToString ());
85-
}
86-
87-
// Called from CoreHttpMessageHandler
88-
internal static TypeDefinition GetHttpMessageHandler (Application app, RuntimeOptions options, ModuleDefinition httpModule, ModuleDefinition? platformModule = null)
89-
{
90-
string? handler;
91-
92-
if (options is not null) {
93-
handler = options.http_message_handler;
94-
} else {
95-
#if !LEGACY_TOOLS
96-
handler = NSUrlSessionHandlerValue;
97-
#else
98-
handler = HttpClientHandlerValue;
99-
#endif
100-
}
101-
TypeDefinition type;
102-
switch (handler) {
103-
#if MONOMAC
104-
case HttpClientHandlerValue:
105-
type = httpModule.GetType ("System.Net.Http", "HttpClientHandler");
106-
break;
107-
case CFNetworkHandlerValue:
108-
type = platformModule!.GetType ("System.Net.Http", "CFNetworkHandler");
109-
break;
110-
case NSUrlSessionHandlerValue:
111-
type = platformModule!.GetType ("Foundation", "NSUrlSessionHandler");
112-
break;
113-
#else
114-
#if !LEGACY_TOOLS
115-
case SocketsHandlerValue:
116-
type = httpModule.GetType ("System.Net.Http", "SocketsHttpHandler");
117-
break;
118-
#else
119-
case HttpClientHandlerValue:
120-
type = httpModule.GetType ("System.Net.Http", "HttpClientHandler");
121-
break;
122-
#endif
123-
case CFNetworkHandlerValue:
124-
type = platformModule!.GetType ("System.Net.Http", "CFNetworkHandler");
125-
break;
126-
case NSUrlSessionHandlerValue:
127-
type = platformModule!.GetType ("System.Net.Http", "NSUrlSessionHandler");
128-
break;
129-
#endif
130-
default:
131-
throw new InvalidOperationException (string.Format ("Unknown HttpMessageHandler `{0}`.", handler));
132-
}
133-
if (type is null)
134-
throw new InvalidOperationException (string.Format ("Cannot load HttpMessageHandler `{0}`.", handler));
135-
return type;
136-
}
137-
#else
138-
139-
internal static RuntimeOptions? Read ()
140-
{
141-
// for iOS NSBundle.ResourcePath returns the path to the root of the app bundle
142-
// for macOS apps NSBundle.ResourcePath returns foo.app/Contents/Resources
143-
// for macOS frameworks NSBundle.ResourcePath returns foo.app/Versions/Current/Resources
144-
Class bundle_finder = new Class (typeof (NSObject.NSObject_Disposer));
145-
var resource_dir = NSBundle.FromClass (bundle_finder).ResourcePath;
146-
var plist_path = GetFileName (resource_dir);
147-
148-
if (!File.Exists (plist_path))
149-
return null;
150-
151-
using (var plist = NSMutableDictionary.FromFile (plist_path)) {
152-
var options = new RuntimeOptions ();
153-
options.http_message_handler = (NSString) plist ["HttpMessageHandler"];
154-
return options;
155-
}
156-
}
157-
15817
// This is invoked by
15918
// System.Net.Http.dll!System.Net.Http.HttpClient.cctor
19+
// https://github.com/dotnet/runtime/blob/6be6c5de821e389c986b0926fb7334017decee54/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs#L146-L152
16020
internal static HttpMessageHandler GetHttpMessageHandler ()
16121
{
162-
var options = RuntimeOptions.Read ();
163-
// all types will be present as this is executed only when the linker is not enabled
164-
var handler_name = options?.http_message_handler;
165-
#if !LEGACY_TOOLS
166-
// Note: no need to handle SocketsHandlerValue here because System.Net.Http handles
167-
// creating a SocketsHttpHandler when configured to do so.
168-
switch (handler_name) {
169-
case CFNetworkHandlerValue:
170-
#pragma warning disable CA1422 // This call site is reachable on: 'ios' 12.2 and later, 'maccatalyst' 12.2 and later, 'macOS/OSX' 12.0 and later, 'tvos' 12.2 and later. 'CFNetworkHandler' is obsoleted on: 'ios' all versions, 'maccatalyst' all versions, 'macOS/OSX' all versions, 'tvos' all versions.
171-
return new CFNetworkHandler ();
172-
#pragma warning restore CA1422
173-
default:
174-
if (handler_name is not null && handler_name != NSUrlSessionHandlerValue)
175-
Runtime.NSLog ($"{handler_name} is not a valid HttpMessageHandler, defaulting to System.Net.Http.NSUrlSessionHandlerValue");
22+
if (Runtime.UseNSUrlSessionHandler)
17623
return new NSUrlSessionHandler ();
177-
}
178-
#else
179-
switch (handler_name) {
180-
case CFNetworkHandlerValue:
181-
return new CFNetworkHandler ();
182-
case NSUrlSessionHandlerValue:
183-
return new NSUrlSessionHandler ();
184-
default:
185-
if (handler_name is not null && handler_name != HttpClientHandlerValue)
186-
Runtime.NSLog ($"{handler_name} is not a valid HttpMessageHandler, defaulting to System.Net.Http.HttpClientHandler");
187-
return new HttpClientHandler ();
188-
}
189-
#endif
190-
}
191-
#endif
19224

193-
// Use either Create() or Read().
194-
RuntimeOptions ()
195-
{
196-
}
25+
if (Runtime.UseCFNetworkHandler)
26+
return new CFNetworkHandler ();
19727

198-
static string GetFileName (string resource_dir)
199-
{
200-
return Path.Combine (resource_dir, "runtime-options.plist");
28+
return new HttpClientHandler ();
20129
}
20230
}
20331
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Net.Http;
4+
5+
using Foundation;
6+
7+
namespace MySimpleApp {
8+
public class Program {
9+
static int Main (string [] args)
10+
{
11+
GC.KeepAlive (typeof (NSObject)); // prevent linking away the platform assembly
12+
13+
Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));
14+
#if HttpClientHandlerFeatureTrimmedAway
15+
var client = new System.Net.Http.HttpClient ();
16+
client.GetStringAsync ("https://microsoft.com");
17+
#endif
18+
19+
return args.Length;
20+
}
21+
}
22+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
5+
</PropertyGroup>
6+
<Import Project="..\shared.csproj" />
7+
</Project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include ../shared.mk

0 commit comments

Comments
 (0)