-
Notifications
You must be signed in to change notification settings - Fork 528
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
[trimming] preserve custom views and $(AndroidHttpClientHandlerType)
#8954
Changes from all commits
2163693
cebeb8a
ef77b4e
aef660c
7d84df7
02e0514
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
using Mono.Linker; | ||
using Mono.Linker.Steps; | ||
using Mono.Tuner; | ||
using Java.Interop.Tools.Cecil; | ||
using Xamarin.Android.Tasks; | ||
|
||
namespace MonoDroid.Tuner { | ||
|
@@ -16,9 +17,46 @@ public class MarkJavaObjects : BaseMarkHandler | |
public override void Initialize (LinkContext context, MarkContext markContext) | ||
{ | ||
base.Initialize (context, markContext); | ||
context.TryGetCustomData ("AndroidHttpClientHandlerType", out string androidHttpClientHandlerType); | ||
context.TryGetCustomData ("AndroidCustomViewMapFile", out string androidCustomViewMapFile); | ||
var customViewMap = MonoAndroidHelper.LoadCustomViewMapFile (androidCustomViewMapFile); | ||
|
||
markContext.RegisterMarkAssemblyAction (assembly => ProcessAssembly (assembly, androidHttpClientHandlerType, customViewMap)); | ||
markContext.RegisterMarkTypeAction (type => ProcessType (type)); | ||
} | ||
|
||
bool IsActiveFor (AssemblyDefinition assembly) | ||
{ | ||
return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); | ||
} | ||
|
||
public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClientHandlerType, Dictionary<string, HashSet<string>> customViewMap) | ||
{ | ||
if (!IsActiveFor (assembly)) | ||
return; | ||
|
||
foreach (var type in assembly.MainModule.Types) { | ||
// Custom HttpMessageHandler | ||
if (!string.IsNullOrEmpty (androidHttpClientHandlerType) && | ||
androidHttpClientHandlerType.StartsWith (type.Name, StringComparison.Ordinal)) { | ||
var assemblyQualifiedName = type.GetPartialAssemblyQualifiedName (Context); | ||
if (assemblyQualifiedName == androidHttpClientHandlerType) { | ||
Annotations.Mark (type); | ||
PreservePublicParameterlessConstructors (type); | ||
continue; | ||
} | ||
} | ||
|
||
// Custom views in Android .xml files | ||
jonathanpeppers marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (!type.ImplementsIJavaObject (cache)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
continue; | ||
if (customViewMap.ContainsKey (type.FullName)) { | ||
Annotations.Mark (type); | ||
PreserveJavaObjectImplementation (type); | ||
} | ||
} | ||
} | ||
|
||
public void ProcessType (TypeDefinition type) | ||
{ | ||
// If this isn't a JLO or IJavaObject implementer, | ||
|
@@ -48,6 +86,21 @@ void PreserveJavaObjectImplementation (TypeDefinition type) | |
PreserveInterfaces (type); | ||
} | ||
|
||
void PreservePublicParameterlessConstructors (TypeDefinition type) | ||
{ | ||
if (!type.HasMethods) | ||
return; | ||
|
||
foreach (var constructor in type.Methods) | ||
{ | ||
if (!constructor.IsConstructor || constructor.IsStatic || !constructor.IsPublic || constructor.HasParameters) | ||
continue; | ||
|
||
PreserveMethod (type, constructor); | ||
break; // We can stop when found | ||
} | ||
} | ||
|
||
void PreserveAttributeSetConstructor (TypeDefinition type) | ||
{ | ||
if (!type.HasMethods) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -408,19 +408,7 @@ public static Dictionary<string, HashSet<string>> LoadCustomViewMapFile (IBuildE | |
var cachedMap = engine?.GetRegisteredTaskObjectAssemblyLocal<Dictionary<string, HashSet<string>>> (mapFile, RegisteredTaskObjectLifetime.Build); | ||
if (cachedMap != null) | ||
return cachedMap; | ||
var map = new Dictionary<string, HashSet<string>> (); | ||
if (!File.Exists (mapFile)) | ||
return map; | ||
foreach (var s in File.ReadLines (mapFile)) { | ||
var items = s.Split (new char [] { ';' }, count: 2); | ||
var key = items [0]; | ||
var value = items [1]; | ||
HashSet<string> set; | ||
if (!map.TryGetValue (key, out set)) | ||
map.Add (key, set = new HashSet<string> ()); | ||
set.Add (value); | ||
} | ||
return map; | ||
return LoadCustomViewMapFile (mapFile); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we "register" var map = LoadCustomViewMapFile (mapFile);
if (map != null) {
engine.RegisterTaskObject (mapFile, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
}
return map; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The RegisterTaskObjectAssemblyLocall call happens inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh the code changed... ah cos of the linker can't use RegisterTaskObject There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry just actually read your comment (its early). The Registration of the file happens in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the new method that doesn't support |
||
} | ||
|
||
public static bool SaveCustomViewMapFile (IBuildEngine4 engine, string mapFile, Dictionary<string, HashSet<string>> map) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
namespace Mono.Android_Test.Library; | ||
|
||
// FIXME: https://github.com/xamarin/xamarin-android/issues/9008 | ||
public class Foo { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of this, is we don't want to iterate over every type in every assembly.
Is
Android.Util.IAttributeSet
required for any custom view?https://github.com/xamarin/xamarin-android/blob/14b70ac32b2a9efefae127795e96ef73124c8557/tests/Mono.Android-Tests/Mono.Android-Test.Library/CustomTextView.cs#L9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See:
IAttributeSet
is used so that the View can obtain any XML attributes specified on the view. The above stack overflow answer has a good example of this:The
AttributeSet
is how theRectangleView
constructor would lookup the values for@app:radiusDimen
,@app:rectangleBackground
, and@app:circleBackground
.I believe, but cannot quickly verify, that the
(Context, IAttributeSet)
constructor is always used/preferred by Android.