-
Notifications
You must be signed in to change notification settings - Fork 564
Description
Related: #5964 (comment)
Question: How "safe" is it to have mutable (non-const, non-readonly) static fields in Xamarin.Android.Build.Tasks.dll which are used by MSBuild tasks?
The primary cause of this question is from investigating Issue #5964, in which the (thread-static!) mutable static field NdkUtil.usingClangNDK was inconsistently initialized, resulting in "not entirely obvious" runtime behavior.
…and it occurs to me that, in the context of MSBuild, I'm not sure how safe it is to have mutable static fields in the first place! Continuing with NdkUtil.usingClangNDK, it's set based on the NDK version, as determined by $(AndroidNdkDirectory)/etc. For a given build, this won't change, but within the IDE, it very well could change, e.g. by the customer changing the Android SDK directory.
It "feels" very "dubious" to have potentially changeable information stored in static fields.
The "obvious" replacement? Instance fields in new classes which can be cached in e.g. IBuildEngine4.GetRegisteredTaskObject(), which -- to my mind, anyway -- allows understanding of the relation of the data to the overall build process.
There are (currently) 27 fields that are static mutable fields:
% git grep '\<static\>.*;' src/Xamarin.Android.Build.Tasks | grep -v readonly | grep -v extern | grep -v Tests/
src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/AndroidLinkConfiguration.cs: static ConditionalWeakTable<LinkContext, AndroidLinkConfiguration> configurations = new ConditionalWeakTable<LinkContext, AndroidLinkConfiguration> ();
src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/ApplyPreserveAttribute.cs: static List<ICustomAttributeProvider> srs_data_contract = new List<ICustomAttributeProvider> ();
src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/ApplyPreserveAttribute.cs: static List<ICustomAttributeProvider> xml_serialization = new List<ICustomAttributeProvider> ();
src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs: static Regex exraArgSplitRegEx = new Regex (@"[\""].+?[\""]|[\''].+?[\'']|[^ ]+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs: pkgmgr.WriteLine ("\tpublic static String[] Assemblies = new String[]{");
src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs: pkgmgr.WriteLine ("\tpublic static String[] Dependencies = new String[]{");
src/Xamarin.Android.Build.Tasks/Tasks/NdkUtils.cs: static bool usingClangNDK;
src/Xamarin.Android.Build.Tasks/Tasks/NdkUtils.cs: public static bool UsingClangNDK => usingClangNDK;
src/Xamarin.Android.Build.Tasks/Tasks/RemoveUnknownFiles.cs: static bool IsWindows = Path.DirectorySeparatorChar == '\\';
src/Xamarin.Android.Build.Tasks/Utilities/Aapt2Daemon.cs: internal static object RegisterTaskObjectKey => TypeFullName;
src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs: // public static final int field = 0xZZ;
src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs: Parse (@"^ public static final int ([^ =]+)\s*=\s*([^;]+);$",
src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs: static CompareTuple compareTuple = new CompareTuple ();
src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs: public static XNamespace AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs: public static XNamespace AndroidXmlToolsNamespace = "http://schemas.android.com/tools";
src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs: static XNamespace androidNs = AndroidXmlNamespace;
src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs: static XNamespace androidToolsNs = AndroidXmlToolsNamespace;
src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.Linker.cs: public static string [] TargetFrameworkDirectories;
src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs: static Lazy<string> uname = new Lazy<string> (GetOSBinDirName, System.Threading.LazyThreadSafetyMode.PublicationOnly);
src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs: public static AndroidVersions SupportedVersions;
src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs: public static AndroidSdkInfo AndroidSdk;
src/Xamarin.Android.Build.Tasks/Utilities/ResourceIdentifier.cs: static Regex validIdentifier = new Regex ($"[^{Identifier}]", RegexOptions.Compiled);
src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs: public static int ZipFlushSizeLimit = 50 * 1024 * 1024;
src/Xamarin.Android.Build.Tasks/Utilities/ZipArchiveEx.cs: public static int ZipFlushFilesLimit = 50;
Note that many of these don't need to be mutable! ZipFlushSizeLimit should be const, validIdentifier and AndroidXmlNamespace should be readonly, etc.
MonoAndroidHelper.SupportedVersions and MonoAndroidHelper.AndroidSdk appear to be "obvious" candidates for a more "Task-oriented" IBuildEngine4.GetRegisteredTaskObject() caching strategy, as well as NdkUtil in general.