From 919fdcf8ee476ecaf6de7f37e3e059976bb1ea57 Mon Sep 17 00:00:00 2001 From: Nathan Westfall Date: Wed, 30 Aug 2017 10:46:18 -0400 Subject: [PATCH 01/29] If building only for x86 or armeabi, x86_64 and armeabi-v7a native libaries are still pulled in when building the APK because the names are being checked using 'contains'. This causes issues when deploying to x86_64 device, but only building for x86 because android will start the VM for x86_64 and get a runtime error because it will be missing the libmonodroid.so. See bug https://bugzilla.xamarin.com/show_bug.cgi?id=47607 --- src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs index cc37c749077..d0f8065af81 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs @@ -534,7 +534,7 @@ void AddNativeLibrariesFromAssemblies (ZipArchiveEx apk, string supportedAbis) var data = ressozip.GetResourceData (); using (var ms = new MemoryStream (data)) { using (var zip = ZipArchive.Open (ms)) { - foreach (var e in zip.Where (x => abis.Any (a => x.FullName.Contains (a)))) { + foreach (var e in zip.Where (x => abis.Any (a => x.FullName.Contains ($"/{a}/")))) { if (e.IsDirectory) continue; var key = e.FullName.Replace ("native_library_imports", "lib"); From d9013148a0080d305a75465997c2aa84f6a173fe Mon Sep 17 00:00:00 2001 From: Nathan Westfall Date: Wed, 30 Aug 2017 16:45:02 -0400 Subject: [PATCH 02/29] add unit tests to confirm correct native libraries are added to apk for https://bugzilla.xamarin.com/show_bug.cgi?id=47607 --- .../PackagingTest.cs | 23 +++++++++++++++++++ .../Android/KnownPackages.cs | 10 ++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 74cdee2e8b4..3a33f4aa2ac 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -158,5 +158,28 @@ public void CheckClassesDexIsIncluded () } } } + + [Test] + public void CheckIncludedNativeLibraries () + { + var proj = new XamarinAndroidApplicationProject () { + IsRelease = true, + }; + proj.Packages.Add(KnownPackages.SQLitePCLRaw_Core); + proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "armeabi;x86"); + using (var b = CreateApkBuilder (Path.Combine ("temp", TestContext.CurrentContext.Test.Name))) { + b.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; + b.ThrowOnBuildFailure = false; + Assert.IsTrue (b.Build (proj), "build failed"); + var apk = Path.Combine (Root, b.ProjectDirectory, + proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); + using (var zip = ZipHelper.OpenZip (apk)) { + var libFiles = zip.Where (x => x.FullName.StartsWith("lib")); + var abiPaths = new string[] { "lib/armeabi/", "lib/x86/" }; + foreach (var file in libFiles) + Assert.IsTrue(abiPaths.Any (x => file.FullName.Contains (x)), $"Apk contains an unnesscary lib file: {file.FullName}"); + } + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs index d8914b720de..bdbb1f693c1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs @@ -322,6 +322,16 @@ public static class KnownPackages }, } }; + public static Package SQLitePCLRaw_Core = new Package { + Id = "SQLitePCLRaw.core", + Version = "1.1.8", + TargetFramework = "monoandroid71", + References = { + new BuildItem.Reference("SQLitePCL") { + MetadataValues = "HintPath=..\\packages\\SQLitePCLRaw.core.1.1.8\\lib\\MonoAndroid\\SQLitePCLRaw.core.dll" + } + } + }; } } From b8dc73286e49c3109b7eb5fc894ec69909d78d76 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 31 Aug 2017 04:29:38 -0400 Subject: [PATCH 03/29] [Xamarin.Android.Build.Tasks] GenerateJavaStubs Rebuilds (#799) Commit 9d131af4 introduced a [unit test failure][m573] on xamarin-android/master: [m573]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/573/ Xamarin.Android.Build.Tests.BuildTest.XA4212 Expected: String containing "warning XA4" But was: Aside: The XA4212 test creates a project with a bad `IJavaObject` type, builds the project -- which triggers an XA4212 error, which *is* observed in the unit test -- then *rebuilds* the project, but this time with `$(AndroidErrorOnCustomJavaObject)`=False. The intention is that the second build should instead elicit an XA4212 *warning*, but otherwise continue just fine. What's interesting about the log file contents is that it shows that the `` task isn't executed *at all*, but it's the `` task which is supposed to emit the warning! Skipping target "_GenerateJavaStubs" because its outputs are up-to-date. Update the `` task so that if it errors out, it *removes* any `` output files. This will ensure that on subsequent builds, the `_GenerateJavaStubs` target won't be inadvertently skipped. (This issue *should* have been caught during the [**macOS+xbuild PR builder** build for PR #797][pr1491]. It *wasn't*, because the `Xamarin.Android.Build.Tests` tests weren't reported. For example, PR #1491 ran 869 tests, while PR #1492 ran 1085! I'm not sure what can be done to better detect and prevent this in the future.) [pr1491]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-pr-builder/1491/ --- .../Tasks/GenerateJavaStubs.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 1c3de9ad422..7729119aa83 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -97,6 +97,15 @@ public override bool Execute () Log.LogMessage (e.ToString ()); } + if (Log.HasLoggedErrors) { + // Ensure that on a rebuild, we don't *skip* the `_GenerateJavaStubs` target, + // by ensuring that the target outputs have been deleted. + Files.DeleteFile (MergedAndroidManifestOutput, Log); + Files.DeleteFile (AcwMapFile, Log); + Files.DeleteFile (Path.Combine (OutputDirectory, "typemap.jm"), Log); + Files.DeleteFile (Path.Combine (OutputDirectory, "typemap.mj"), Log); + } + return !Log.HasLoggedErrors; } From a953d3f1f0d24444c3843d05d35ec98ebab1e8dd Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 31 Aug 2017 09:41:00 -0400 Subject: [PATCH 04/29] [Xamarin.Android.Build.Tasks] AOT+LLVM needs minSdkVersion (#795) Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=58029 Scenario: Build a project with: * `$(Configuration)`=Release * `$(AotAssemblies)`=True * `$(EnableLLVM)`=True * `$(TargetFrameworkVersion)`=v7.1 (API-25) * `//uses-sdk/@android:minSdkVersion`=10 (in `AndroidManifest.xml`) * with Android NDK r12b or later * on particular hardware devices, e.g. a Nexus 5. Actual results: the app runs, but the AOT'd images aren't used: AOT: image 'Xamarin.Android.Support.v7.AppCompat.dll.so' not found: dlopen failed: cannot locate symbol "__aeabi_memset" referenced by "/data/app/com.companyname.App1-1/lib/arm/libaot-Xamarin.Android.Support.v7.AppCompat.dll.so"... The `__aeabi_memset` symbol can't be found, preventing e.g. `Xamarin.Android.Support.v7.AppCompat.dll.so` from being used. Meaning the app pays the build overhead and size penalty of AOT+LLVM, but doesn't get anything out of it; only the JIT is used. The [cause of the missing `__aeabi_memset` symbol][0] is that we're using the NDK paths which corresponds with `$(TargetFrameworkVersion)`, *not* the NDK paths which correspond with `//uses-sdk/@android:minSdkVersion`. Because of this, if you use the `.apk` on a platform which is >= `minSdkVersion` but less than `$(TargetFrameworkVersion)`, the AOT images won't be used. [0]: https://github.com/android-ndk/ndk/issues/126 Fix this by updating the `` task to instead use the `//uses-sdk/@android:minSdkVersion` value. This ensures that we use NDK paths which correspond to the app's minimum supported API level, which should allow the AOT images to be loaded on downlevel devices. --- src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs | 20 +++++++++++++++++-- .../Xamarin.Android.Build.Tests/BuildTest.cs | 18 +++++++++++++++++ .../Xamarin.Android.Common.targets | 1 + 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs index b6ec4329499..752845b76e5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs @@ -41,6 +41,9 @@ public class Aot : AsyncTask [Required] public string AndroidApiLevel { get; set; } + [Required] + public ITaskItem ManifestFile { get; set; } + [Required] public ITaskItem[] ResolvedAssemblies { get; set; } @@ -165,9 +168,22 @@ static bool ValidateAotConfiguration (TaskLoggingHelper log, AndroidTargetArch a return true; } - static int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch) + int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch) { - int level = int.Parse(androidApiLevel); + var manifest = AndroidAppManifest.Load (ManifestFile.ItemSpec, MonoAndroidHelper.SupportedVersions); + + int level; + if (manifest.MinSdkVersion.HasValue) { + level = manifest.MinSdkVersion.Value; + } + else if (int.TryParse (androidApiLevel, out level)) { + // level already set + } + else { + // Probably not ideal! + level = MonoAndroidHelper.SupportedVersions.MaxStableVersion.ApiLevel; + } + // Some Android API levels do not exist on the NDK level. Workaround this my mapping them to the // most appropriate API level that does exist. if (level == 6 || level == 7) level = 5; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 7273c967718..7eab656f9d5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Xml.Linq; using Microsoft.Build.Framework; using NUnit.Framework; @@ -209,12 +210,29 @@ public void BuildAotApplication (string supportedAbis, bool enableLLVM, bool exp proj.SetProperty (KnownProperties.TargetFrameworkVersion, "v5.1"); proj.SetProperty (KnownProperties.AndroidSupportedAbis, supportedAbis); proj.SetProperty ("EnableLLVM", enableLLVM.ToString ()); + if (enableLLVM) { + // Set //uses-sdk/@android:minSdkVersion so that LLVM uses the right libc.so + proj.AndroidManifest = $@" + + + + +"; + } using (var b = CreateApkBuilder (path)) { b.ThrowOnBuildFailure = false; b.Verbosity = LoggerVerbosity.Diagnostic; Assert.AreEqual (expectedResult, b.Build (proj), "Build should have {0}.", expectedResult ? "succeeded" : "failed"); if (!expectedResult) return; + if (enableLLVM) { + // LLVM passes a direct path to libc.so, and we need to use the libc.so + // which corresponds to the *minimum* SDK version specified in AndroidManifest.xml + // Since we overrode minSdkVersion=10, that means we should use libc.so from android-9. + var rightLibc = new Regex (@"^\s*\[AOT\].*cross-.*--llvm.*,ld-flags=.*android-9.arch-.*.usr.lib.libc\.so", RegexOptions.Multiline); + var m = rightLibc.Match (b.LastBuildOutput); + Assert.IsTrue (m.Success, "AOT+LLVM should use libc.so from minSdkVersion!"); + } foreach (var abi in supportedAbis.Split (new char [] { ';' })) { var libapp = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "bundles", abi, "libmonodroid_bundle_app.so"); diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index a8d5f226ef5..91e6a0c2f54 100755 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2159,6 +2159,7 @@ because xbuild doesn't support framework reference assemblies. AndroidAotMode="$(AndroidAotMode)" AndroidNdkDirectory="$(_AndroidNdkDirectory)" AndroidApiLevel="$(_AndroidApiLevel)" + ManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml" SupportedAbis="$(_BuildTargetAbis)" AndroidSequencePointsMode="$(_SequencePointsMode)" AotAdditionalArguments="$(AndroidAotAdditionalArguments)" From 6b54d6dd26cf3d8e324b4dd2a7563c32d323940a Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Thu, 31 Aug 2017 10:17:53 -0400 Subject: [PATCH 05/29] Bump $(ProductVersion) to 8.0.99 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We (try to) base Xamarin.Android product versions on the latest Android versions. Android 8.0 Oreo™ [has been announced][0], and since the xamarin-android/d15-4 branch includes an API-26/v8.0 binding, the overall product version for d15-4 should *also* be bumped to v8.0. [0]: https://www.android.com/versions/oreo-8-0/ As xamarin-android/master is tracking the *next* Xamarin.Android version, bump `$(ProductVersion)` to v8.0.99 for eventual release as v8.1.0. --- Configuration.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Configuration.props b/Configuration.props index 7ef4f8fdf0a..ef23fd5df98 100644 --- a/Configuration.props +++ b/Configuration.props @@ -12,7 +12,7 @@ Condition=" '$(DoNotLoadOSProperties)' != 'True' " /> - 7.4.99 + 8.0.99 26 v8.0 From 79989b7c3cccd933d819916c40fd2c77e8889a46 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 31 Aug 2017 16:40:12 +0200 Subject: [PATCH 06/29] [Mono.Android-Tests] Fix stat(1) arguments on Linux (#801) macOS uses *BSD command-line tools which often take different parameters than the Linux ones. This is the case with **stat**(1) which not only expects different command line parameters but also has different meaning of various format placeholders (in this case `%z` means "file size in bytes" on macOS but "file time stamp timezone in human readable format"). This fixes **stat**(1) invocation on Linux. --- src/Mono.Android/Test/Mono.Android-Tests.projitems | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mono.Android/Test/Mono.Android-Tests.projitems b/src/Mono.Android/Test/Mono.Android-Tests.projitems index 71921fdcb1a..51854ea4fd0 100644 --- a/src/Mono.Android/Test/Mono.Android-Tests.projitems +++ b/src/Mono.Android/Test/Mono.Android-Tests.projitems @@ -16,7 +16,8 @@ - + + From 32ddcb8b878adb761cb876fbceefeb038b742a00 Mon Sep 17 00:00:00 2001 From: Bret Johnson Date: Thu, 31 Aug 2017 14:41:46 -0400 Subject: [PATCH 07/29] [Xamarin.Android.Build.Tasks] Preserve set_ShadowCopyDirectories (#803) Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=59115 `monodroid_create_appdomain()` requires that the `AppDomainSetup.set_ShadowCopyDirectories` property exist, so that it can be called. Unfortunately, the linker may remove this property, which results in a SIGSEGV if it's been removed: C [libmonosgen-2.0.dylib+0x20bc9c] mono_property_set_value+0xc C [libmono-android.debug.dylib+0x154fe] monodroid_property_set+0xbe C [libmono-android.debug.dylib+0x15268] monodroid_create_appdomain+0x248 C [libmono-android.debug.dylib+0xf159] create_domain+0x149 C [libmono-android.debug.dylib+0xe439] create_and_initialize_domain+0x69 C [libmono-android.debug.dylib+0xe89d] Java_mono_android_Runtime_createNewContext+0x7d Add `AppDomainSetup.set_ShadowCopyDirectories` to the linker's preserve list, so that the Android Designer can work as intended. --- .../Linker/PreserveLists/mscorlib.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/mscorlib.xml b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/mscorlib.xml index c3fccbe5402..08afc6be33e 100644 --- a/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/mscorlib.xml +++ b/src/Xamarin.Android.Build.Tasks/Linker/PreserveLists/mscorlib.xml @@ -16,6 +16,7 @@ + From fc8e48ef1f33d09563e08ce51704c4ec56e14a14 Mon Sep 17 00:00:00 2001 From: Nathan Westfall Date: Thu, 31 Aug 2017 22:50:01 -0400 Subject: [PATCH 08/29] changed native library test to only x86 --- .../Tests/Xamarin.Android.Build.Tests/PackagingTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index 3a33f4aa2ac..5edba691eed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -166,7 +166,7 @@ public void CheckIncludedNativeLibraries () IsRelease = true, }; proj.Packages.Add(KnownPackages.SQLitePCLRaw_Core); - proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "armeabi;x86"); + proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidSupportedAbis, "x86"); using (var b = CreateApkBuilder (Path.Combine ("temp", TestContext.CurrentContext.Test.Name))) { b.Verbosity = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic; b.ThrowOnBuildFailure = false; @@ -174,8 +174,8 @@ public void CheckIncludedNativeLibraries () var apk = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "bin", "UnnamedProject.UnnamedProject.apk"); using (var zip = ZipHelper.OpenZip (apk)) { - var libFiles = zip.Where (x => x.FullName.StartsWith("lib")); - var abiPaths = new string[] { "lib/armeabi/", "lib/x86/" }; + var libFiles = zip.Where (x => x.FullName.StartsWith("lib/") && !x.FullName.Equals("lib/", StringComparison.InvariantCultureIgnoreCase)); + var abiPaths = new string[] { "lib/x86/" }; foreach (var file in libFiles) Assert.IsTrue(abiPaths.Any (x => file.FullName.Contains (x)), $"Apk contains an unnesscary lib file: {file.FullName}"); } From 9646b0a9a10b61f5bc3fe4f6ea9bb7bf3fa3c894 Mon Sep 17 00:00:00 2001 From: Daniel Cazzulino Date: Fri, 1 Sep 2017 11:12:37 -0300 Subject: [PATCH 09/29] [create-vsix] Always version the output `.vsix` file (#806) When the VSSDK builds the VSIX container, it generates a manifest (`catalog.json`) placed inside it that has the resulting filename in it. This manifest is used in alpha pack generation (by XVS) to determine the payloads to include. This is done by invoking the VSMAN tool (manifest generation thing) uses the contents of the catalog. If the filename inside the catalog doesn't match the actual filename included in the alpha pack manifest, installation fails, so we need to ensure the filename is changed early enough in the process so that it's consistent in the embedded manifest. --- build-tools/create-vsix/create-vsix.targets | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build-tools/create-vsix/create-vsix.targets b/build-tools/create-vsix/create-vsix.targets index 5cbad4f8e7c..4c2344a7879 100644 --- a/build-tools/create-vsix/create-vsix.targets +++ b/build-tools/create-vsix/create-vsix.targets @@ -87,6 +87,14 @@ $(ProductVersion).$(XAVersionCommitCount) + + + $([System.IO.Path]::GetFileName('$(VsixPath)')) + $(OutDir)$(TargetVsixContainerName) + + @@ -114,11 +122,11 @@ Date: Fri, 1 Sep 2017 18:26:10 +0100 Subject: [PATCH 10/29] [Xamarin.Android.Build.Tests] Fix Errors in the Designer Tests (#807) We made an assumption when the test was written that the old `Resource.designer.cs` was going to be deleted in projects when using `$(AndroidUseIntermediateDesignerFile)`. The decision was changed so it would jsut be ignored. So the existing check that is should not exist was wrong. That said it did not fail because we did not include the `Root` proeprty in the path so it always passed because that file did not exist in the location we were checking. The change to nunit3 changed that as because of the way the working directory is set that check now failed. Because the old incorrect path was not correct.. doh. So a better check is to make sure that the old file is just emtpy. We almost empty since the the project tools write the file we end up with a Unicode marker. We also update the XamarinAndroidApplicationProject so that we can override the `$(EmbedAssembliesIntoApk)`. This is required for various unit tests. The way it currently worked was that no matter what you set.. you always got the default. This worked for the OSS repo as we don't use the shared-runtime. But for the monodroid stuff, we need to be able to change that value. This was stopping the test projects doing that. --- .../AndroidUpdateResourcesTest.cs | 8 ++++---- .../Android/XamarinAndroidApplicationProject.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index 558c41c10a5..a5254a57b5a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -435,9 +435,9 @@ public void CheckOldResourceDesignerIsNotUsed (bool isRelease, ProjectLanguage l if (File.Exists (designer)) File.Delete (Path.Combine (Root, b.ProjectDirectory, designer)); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - Assert.IsFalse (File.Exists (Path.Combine (b.ProjectDirectory, "Resources", - "Resource.designer" + proj.Language.DefaultDesignerExtension)), - "{0} should not exists", designer); + var fi = new FileInfo (Path.Combine (Root, b.ProjectDirectory, designer)); + Assert.IsFalse (fi.Length > new [] { 0xef, 0xbb, 0xbf, 0x0d, 0x0a }.Length, + "{0} should not contain anything.", designer); var outputFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "Resource.Designer" + proj.Language.DefaultDesignerExtension); Assert.IsTrue (File.Exists (outputFile), "Resource.Designer{1} should have been created in {0}", @@ -467,7 +467,7 @@ public void CheckOldResourceDesignerWithWrongCasingIsRemoved (bool isRelease, Pr Assert.IsNotNull (designer, $"Failed to retrieve the Resource.designer.{proj.Language.DefaultDesignerExtension}"); designer.Deleted = true; Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - Assert.IsFalse (File.Exists (Path.Combine (b.ProjectDirectory, "Resources", + Assert.IsFalse (File.Exists (Path.Combine (Root, b.ProjectDirectory, "Resources", "Resource.designer" + proj.Language.DefaultDesignerExtension)), "{0} should not exists", designer.Include ()); var outputFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs index 98ce1aa683e..9b7359368f3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XamarinAndroidApplicationProject.cs @@ -43,8 +43,8 @@ public XamarinAndroidApplicationProject (string debugConfigurationName = "Debug" SetProperty ("AndroidManifest", "Properties\\AndroidManifest.xml"); SetProperty (DebugProperties, "AndroidLinkMode", "None"); SetProperty (ReleaseProperties, "AndroidLinkMode", "SdkOnly"); - SetProperty (DebugProperties, "EmbedAssembliesIntoApk", "False"); - SetProperty (ReleaseProperties, "EmbedAssembliesIntoApk", "True"); + SetProperty (DebugProperties, "EmbedAssembliesIntoApk", "False", "'$(EmbedAssembliesIntoApk)' == ''"); + SetProperty (ReleaseProperties, "EmbedAssembliesIntoApk", "True", "'$(EmbedAssembliesIntoApk)' == ''"); AndroidManifest = default_android_manifest; LayoutMain = default_layout_main; From 0d800426cc24e7e469bd2119163dc182c5ebaebb Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 1 Sep 2017 19:08:12 -0400 Subject: [PATCH 11/29] [Xamarin.Android.Build.Tasks] minSdkVersion checks on 32-bit (#812) The `BuildAotApplication()` test additions from commit a953d3f1 don't work when `supportedAbis` is a 64-bit platform such as `x86_64` or `arm64-v8a`, because the test checks for `android-9`, which is only going to be valid for 32-bit architectures. (64-bit architecture support requires API-21, iirc.) Update the minSdkVersion path check to only execute when dealing with 32-bit architectures. --- .../Tests/Xamarin.Android.Build.Tests/BuildTest.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 7eab656f9d5..b8edb54f55a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -210,7 +210,8 @@ public void BuildAotApplication (string supportedAbis, bool enableLLVM, bool exp proj.SetProperty (KnownProperties.TargetFrameworkVersion, "v5.1"); proj.SetProperty (KnownProperties.AndroidSupportedAbis, supportedAbis); proj.SetProperty ("EnableLLVM", enableLLVM.ToString ()); - if (enableLLVM) { + bool checkMinLlvmPath = enableLLVM && (supportedAbis == "armeabi-v7a" || supportedAbis == "x86"); + if (checkMinLlvmPath) { // Set //uses-sdk/@android:minSdkVersion so that LLVM uses the right libc.so proj.AndroidManifest = $@" @@ -225,7 +226,7 @@ public void BuildAotApplication (string supportedAbis, bool enableLLVM, bool exp Assert.AreEqual (expectedResult, b.Build (proj), "Build should have {0}.", expectedResult ? "succeeded" : "failed"); if (!expectedResult) return; - if (enableLLVM) { + if (checkMinLlvmPath) { // LLVM passes a direct path to libc.so, and we need to use the libc.so // which corresponds to the *minimum* SDK version specified in AndroidManifest.xml // Since we overrode minSdkVersion=10, that means we should use libc.so from android-9. From b28fbfc0b5b5e7cb489da9306d46542b0be1d4db Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Sat, 2 Sep 2017 15:28:36 -0400 Subject: [PATCH 12/29] Bump to mono/2017-04/63e8c46a (#813) --- external/mono | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/mono b/external/mono index 54108f9522e..63e8c46ab0f 160000 --- a/external/mono +++ b/external/mono @@ -1 +1 @@ -Subproject commit 54108f9522e526012d1fb16cda0d1c40b8048ff4 +Subproject commit 63e8c46ab0fb0d1744a8f7a855e756c1d69fcf02 From a15ee0a70a81ba771ceabf4d9bd0eb37157bfdef Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 1 Sep 2017 16:09:35 -0400 Subject: [PATCH 13/29] [build] Fix GenerateJavaCallableWrappers dependencies Commit ff28d572 updated some of the Java source code that is included into `mono.android.jar`, which needs to be kept synchronized with the `libmono-android*` ("libmonodroid")` native libraries. Unfortunately, the build system didn't know about this dependency; the `GenerateJavaCallableWrappers` target only executes when `Mono.Android.dll` is updated, but commit ff28d572 didn't have anything which would cause `Mono.Android.dll` to be updated. As a result, *pre-existing build trees* that had `Mono.Android.dll` and `mono.android.jar` files from *before* commit ff28d572, when updated to be at ff28d572 or later, would rebuild `src/Xamarin.Android.Build.Tasks` -- which contains `MonoPackageManager.java` -- but would *not* rebuild `mono.android.jar`. This would result in build-time failures when building the unit tests: obj/Release/android/src/mono/MonoPackageManager.java(59,7): error : error: incompatible types: String[] cannot be converted to String Update the `GenerateJavaCallableWrappers` target to include `@(JavaCallableWrapperSource)` as an input dependency, and update `Mono.Android.targets` to include `src/Mono.Android/java/**` into `@(JavaCallableWrapperSource)`. This will ensure that the next time the Mono.Android-related Java sources are updated, we properly rebuild `mono.android.jar`. --- build-tools/scripts/JavaCallableWrappers.targets | 4 ++-- src/Mono.Android/Mono.Android.targets | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-tools/scripts/JavaCallableWrappers.targets b/build-tools/scripts/JavaCallableWrappers.targets index ee0ea85daef..d2159085488 100644 --- a/build-tools/scripts/JavaCallableWrappers.targets +++ b/build-tools/scripts/JavaCallableWrappers.targets @@ -2,7 +2,7 @@ @@ -20,7 +20,7 @@ diff --git a/src/Mono.Android/Mono.Android.targets b/src/Mono.Android/Mono.Android.targets index f298d08497b..1d948904634 100644 --- a/src/Mono.Android/Mono.Android.targets +++ b/src/Mono.Android/Mono.Android.targets @@ -104,7 +104,7 @@ 1.6 - <_CommonJavaSources Include="java\**\*.java" /> + Date: Mon, 4 Sep 2017 20:51:04 +0900 Subject: [PATCH 14/29] [msbuild] Prepare for d8 (new dex compiler) (#793) You can get d8 compiler sources from https://r8.googlesource.com/ d8 expects slightly different set of command line arguments. There is no --no-strict nor --dex arguments, and --output= is not accepted. Classes must be explicitly specified (no assumption on "directory == classes"). With all these changes, I could build apk with this command line: DxJarPath=/path/to/d8.jar DxExtraArguments="--debug" msbuild MyProject.csproj /t:SignAndroidPackage With this change, anyone can offer custom NuGet package for d8 compiler with its own custom MSBuild targets that specifies DxJarPath and DxExtraArguments (just like what we could do for facebook proguard). --- .../Tasks/CompileToDalvik.cs | 11 +++++++---- .../Xamarin.Android.Common.targets | 8 ++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs index 811d8c81070..67e71d4c4a4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs @@ -20,6 +20,8 @@ public class CompileToDalvik : JavaToolTask public string DxJarPath { get; set; } + public string DxExtraArguments { get; set; } + public string JavaToolPath { get; set; } [Required] @@ -59,6 +61,7 @@ public override bool Execute () Log.LogDebugMessage (" ToolExe: {0}", ToolExe); Log.LogDebugMessage (" ToolPath: {0}", ToolPath); Log.LogDebugMessage (" UseDx: {0}", UseDx); + Log.LogDebugMessage (" DxExtraArguments: {0}", DxExtraArguments); Log.LogDebugMessage (" MultiDexEnabled: {0}", MultiDexEnabled); Log.LogDebugMessage (" MultiDexMainDexListFile: {0}", MultiDexMainDexListFile); Log.LogDebugTaskItems (" JavaLibrariesToCompile:", JavaLibrariesToCompile); @@ -97,23 +100,23 @@ protected override string GenerateCommandLineCommands () cmd.AppendSwitchIfNotNull("-Xmx", JavaMaximumHeapSize); cmd.AppendSwitchIfNotNull ("-jar ", Path.Combine (DxJarPath)); - cmd.AppendSwitch ("--no-strict"); } - cmd.AppendSwitch ("--dex"); + cmd.AppendSwitch (DxExtraArguments); if (MultiDexEnabled) { cmd.AppendSwitch ("--multi-dex"); cmd.AppendSwitchIfNotNull ("--main-dex-list=", MultiDexMainDexListFile); } - cmd.AppendSwitchIfNotNull ("--output=", Path.GetDirectoryName (ClassesOutputDirectory)); + cmd.AppendSwitchIfNotNull ("--output ", Path.GetDirectoryName (ClassesOutputDirectory)); // .jar files if (File.Exists (OptionalObfuscatedJarFile)) cmd.AppendFileNameIfNotNull (OptionalObfuscatedJarFile); else { - cmd.AppendFileNameIfNotNull (ClassesOutputDirectory); + foreach (var cls in Directory.GetFiles (ClassesOutputDirectory, "*.class", SearchOption.AllDirectories)) + cmd.AppendFileNameIfNotNull (cls); foreach (var jar in JavaLibrariesToCompile) cmd.AppendFileNameIfNotNull (jar.ItemSpec); } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 91e6a0c2f54..08c3fadcac2 100755 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -796,6 +796,13 @@ because xbuild doesn't support framework reference assemblies. Condition="'$(DxJarPath)' == ''" /> + + + + + Date: Tue, 5 Sep 2017 16:00:27 +0200 Subject: [PATCH 15/29] [docs] What about Instant Run? (#817) --- InstantApps.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 InstantApps.md diff --git a/InstantApps.md b/InstantApps.md new file mode 100644 index 00000000000..e3fb4c63206 --- /dev/null +++ b/InstantApps.md @@ -0,0 +1,62 @@ +Android Instant Apps and Xamarin Android +======================================== + +Synopsis +-------- + +Support for Android Instant Apps in Xamarin Android is currently impossible/impractical. + + +Introductiona +------------ + +[Android Instant Apps](https://developer.android.com/topic/instant-apps/index.html) is a new Android +feature that allows application developers to create applications which don't need to be fully installed +on the user's device but rather started "instantly" by clicking a link to the application. + +This is essentially implemented by creating a number of individual .apk packages which contain various +application features, most commonly accompanied by an Activity which presents the feature to the user. + +To support "instant" launching of the applications as well as to ascertain security of applications +Google imposed a number of limitations on such apps described in the following sections. + + +Limitations +=========== + +https://developer.android.com/topic/instant-apps/prepare.html#restricted_features + + +Limitation 1: size +------------------ + +Each instant app consists of at least a single apk (called the **base package**) and zero or more +*feature* apk packages which are installed on demand. When the user clicks application link they +are taken to the Play Store and the base apk is downloaded, installed on the system and cached for +future use. If the application consists of more apks they are downloaded whenever the user, or an +Activity in the base or feature apk, opens a link which corresponds to the requested feature/actvity. +To ensure quick download times, Google imposed a limit of 4MB to any individual apk as well as to the +base + feature apk size. +Instant App developers are encouraged to put as few assets in the .apk as possible and download the +rest when the app is first started. + +**Impact on Xamarin.Android**: XA nearly pushes the size limit with a simple "Hello World" application +where, in Release build, the Mono runtime is nearly 3MB in size - not including the BCL, SDK and +application assemblies. While it would be possible to download the Mono runtime and the assemblies on +the app startup (XA app include a small Java stub responsible for launching of the managed application), +the solution would probably be very unwieldy and impractical. + + +Limitation 2: native code +------------------------- + +Instant Apps are not allowed to contain and run any arbitrary native code/libraries. This limitation +exists most probably for security reasons. It is also disallowed to dynamically load any code other +than the Instant Apps runtime. + +**Impact on Xamarin.Android**: it prevents XA applications from running since both +the Mono and the Xamarin.Android runtimes are implemented as shared libraries (we also need, depending +on application, the Sqlite and Boring TLS libraries). In order to support Instant Apps in Xamarin.Android, +its runtime as well as the Mono runtime would have to be included in the set of allowed native code +libraries by Google/Android. + From 069cb7e66568a115ef873e7fed45a797f4fec5a9 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Tue, 5 Sep 2017 23:04:53 +0900 Subject: [PATCH 16/29] [install] Fix install target in Makefile (#814) Dunno where if-then-fi without ';' worked, but it doesn't on Ubuntu 17.04. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 86cf540d5bd..1c3bbb1a975 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ install:: ln -s "$(prefix)/lib/xamarin.android/xbuild/Xamarin/Android/" "$(prefix)/lib/mono/xbuild/Xamarin/Android" ln -s "$(prefix)/lib/xamarin.android/xbuild-frameworks/MonoAndroid/" "$(prefix)/lib/mono/xbuild-frameworks/MonoAndroid" if [ ! -e "$(prefix)/bin/mono" ]; then \ - cp tools/scripts/xabuild "$(prefix)/bin/xabuild" + cp tools/scripts/xabuild "$(prefix)/bin/xabuild"; \ fi uninstall:: From bd18b365ad6b5fb1ae6223943fae9227977251a7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 5 Sep 2017 12:52:25 -0400 Subject: [PATCH 17/29] Bump to mono/2017-06/cb6a2fc7 Start using Mono 5.4.0! Bump `$(MonoRequiredMinimumVersion)` to 5.4.0.147. Bumps to linker/master/9fc2a24b Bumps to llvm/master/21492ec9 Bumps to xamarin-android-api-compatibility/master/b26743f1 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=580 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=17325 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=43988 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=44907 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=46482 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=51791 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=52508 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=53038 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=53202 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=53244 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=53792 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54159 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54322 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54388 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54448 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54485 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54976 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=54991 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55041 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55083 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55095 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55148 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55348 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55400 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55577 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55603 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55604 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=55681 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56081 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56111 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56202 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56240 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56242 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56247 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56452 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56462 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56493 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56499 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56567 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56611 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56616 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56627 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56684 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56694 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56814 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56821 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=56824 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57002 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57222 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57232 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57242 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57301 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57505 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57629 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57691 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57744 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57796 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57850 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57851 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57930 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=57959 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58114 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58210 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58344 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58361 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58399 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58421 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58446 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58454 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58738 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58782 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58829 Context: https://bugzilla.xamarin.com/show_bug.cgi?id=58877 --- .gitmodules | 4 ++-- Configuration.props | 4 ++-- build-tools/dependencies/dependencies.projitems | 4 ++-- external/linker | 2 +- external/llvm | 2 +- external/mono | 2 +- external/xamarin-android-api-compatibility | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitmodules b/.gitmodules index b21152f4ac3..755d45969d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,7 @@ [submodule "external/mono"] path = external/mono url = https://github.com/mono/mono.git - branch = 2017-04 + branch = 2017-06 [submodule "external/mxe"] path = external/mxe url = https://github.com/xamarin/mxe.git @@ -39,4 +39,4 @@ [submodule "xamarin-android-api-compatibility"] path = external/xamarin-android-api-compatibility url = https://github.com/xamarin/xamarin-android-api-compatibility.git - branch = d15-4 + branch = master diff --git a/Configuration.props b/Configuration.props index ef23fd5df98..97a03949f09 100644 --- a/Configuration.props +++ b/Configuration.props @@ -53,8 +53,8 @@ $(MSBuildThisFileDirectory)external\Java.Interop $(MSBuildThisFileDirectory)external\llvm $(MSBuildThisFileDirectory)external\mono - 5.2.0 - $(MonoRequiredMinimumVersion).114 + 5.4.0 + $(MonoRequiredMinimumVersion).147 $(MSBuildThisFileDirectory)external\linker $(MSBuildThisFileDirectory)external\opentk $(MSBuildThisFileDirectory)external\libzip diff --git a/build-tools/dependencies/dependencies.projitems b/build-tools/dependencies/dependencies.projitems index b59fb788231..12566b9f53b 100644 --- a/build-tools/dependencies/dependencies.projitems +++ b/build-tools/dependencies/dependencies.projitems @@ -1,7 +1,7 @@ - <_DarwinMonoFramework>MonoFramework-MDK-5.2.0.114.macos10.xamarin.universal.pkg + <_DarwinMonoFramework>MonoFramework-MDK-5.4.0.147.macos10.xamarin.universal.pkg <_AptGetInstall>apt-get -f -u install @@ -58,7 +58,7 @@ $(MonoRequiredMinimumVersion) $(MonoRequiredDarwinMinimumVersion) $(MSBuildThisFileDirectory)..\scripts\mono-version - https://bosstoragemirror.blob.core.windows.net/wrench/mono-2017-04/8a/8a4958ae3861143b55981cef3843c328462041f8/$(_DarwinMonoFramework) + https://bosstoragemirror.blob.core.windows.net/wrench/mono-2017-06/28/28a417c2c0d1a2d1231d8b0a5beea3201208b57d/$(_DarwinMonoFramework) installer -pkg "$(AndroidToolchainCacheDirectory)\$(_DarwinMonoFramework)" -target / diff --git a/external/linker b/external/linker index 07b07ef75fa..9fc2a24b5fc 160000 --- a/external/linker +++ b/external/linker @@ -1 +1 @@ -Subproject commit 07b07ef75fa1858253af45af6fe30812a5a1655c +Subproject commit 9fc2a24b5fc389a3bc3bde85efa1e39b43f1fce0 diff --git a/external/llvm b/external/llvm index dbb6fdffdeb..21492ec92e2 160000 --- a/external/llvm +++ b/external/llvm @@ -1 +1 @@ -Subproject commit dbb6fdffdeb780d11851a6be77c209bd7ada4bd3 +Subproject commit 21492ec92e255a43bc6b687468f1eb18a635d94e diff --git a/external/mono b/external/mono index 63e8c46ab0f..cb6a2fc7ff0 160000 --- a/external/mono +++ b/external/mono @@ -1 +1 @@ -Subproject commit 63e8c46ab0fb0d1744a8f7a855e756c1d69fcf02 +Subproject commit cb6a2fc7ff00b7b8b5f41f08b7a1d60f3cf8d2e6 diff --git a/external/xamarin-android-api-compatibility b/external/xamarin-android-api-compatibility index 64714d845d3..b26743f1624 160000 --- a/external/xamarin-android-api-compatibility +++ b/external/xamarin-android-api-compatibility @@ -1 +1 @@ -Subproject commit 64714d845d3b5dd256b7feb0c0ff1d65f49e652c +Subproject commit b26743f16240ae3cdab4d40ce8826c0d4cdfff3f From 320d773824a25e12c8f42390e61cf3475d2278f2 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 5 Sep 2017 21:17:00 +0200 Subject: [PATCH 18/29] [tests] Merge runtime test timing measurements into one plot (#815) - also dump logcat only once per target run, we don't need to differentiate it for various tests, as they are batched over one emulator instance --- build-tools/scripts/UnitTestApks.targets | 13 ++++++++----- src/Mono.Android/Test/Mono.Android-Tests.projitems | 5 +++-- src/Mono.Android/Test/timing-definitions-Debug.txt | 6 ++++++ .../Test/timing-definitions-Release-Aot.txt | 6 ++++++ .../Test/timing-definitions-Release.txt | 6 ++++++ .../Xamarin.Android.JcwGen-Tests.projitems | 1 + .../Xamarin.Android.Locale-Tests.projitems | 1 + 7 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/Mono.Android/Test/timing-definitions-Debug.txt create mode 100644 src/Mono.Android/Test/timing-definitions-Release-Aot.txt create mode 100644 src/Mono.Android/Test/timing-definitions-Release.txt diff --git a/build-tools/scripts/UnitTestApks.targets b/build-tools/scripts/UnitTestApks.targets index ba4524c29de..b66fcc08552 100644 --- a/build-tools/scripts/UnitTestApks.targets +++ b/build-tools/scripts/UnitTestApks.targets @@ -146,11 +146,14 @@ - <_DefinitionsFilename Condition=" '%(UnitTestApk.TimingDefinitionsFilename)' == '' ">$(MSBuildThisFileDirectory)/TimingDefinitions.txt - <_DefinitionsFilename Condition=" '%(UnitTestApk.TimingDefinitionsFilename)' != '' ">%(UnitTestApk.TimingDefinitionsFilename) - <_LogcatFilenameEnd>-logcat-$(Configuration)$(_AotName).txt + <_LogcatFilename>logcat-$(Configuration)$(_AotName).txt - - + + diff --git a/src/Mono.Android/Test/Mono.Android-Tests.projitems b/src/Mono.Android/Test/Mono.Android-Tests.projitems index 51854ea4fd0..65b62e182ce 100644 --- a/src/Mono.Android/Test/Mono.Android-Tests.projitems +++ b/src/Mono.Android/Test/Mono.Android-Tests.projitems @@ -2,7 +2,7 @@ - <_MonoAndroidTestResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-$(Configuration)$(_AotName).xml + <_MonoAndroidTestResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests.xml <_MonoAndroidTestPackage>Mono.Android_Tests <_MonoAndroidTestApkFile>$(OutputPath)Mono.Android_Tests-Signed.apk <_MonoAndroidTestApkSizesInput>apk-sizes-$(_MonoAndroidTestPackage)-$(Configuration)$(_AotName).txt @@ -12,10 +12,11 @@ $(_MonoAndroidTestPackage) xamarin.android.runtimetests.TestInstrumentation $(_MonoAndroidTestResultsPath) + $(MSBuildThisFileDirectory)timing-definitions-$(Configuration)$(_AotName).txt - + diff --git a/src/Mono.Android/Test/timing-definitions-Debug.txt b/src/Mono.Android/Test/timing-definitions-Debug.txt new file mode 100644 index 00000000000..171cf2ef150 --- /dev/null +++ b/src/Mono.Android/Test/timing-definitions-Debug.txt @@ -0,0 +1,6 @@ +# measure time of last monodroid-timing message appearance +last-Debug=monodroid-timing:\s+(?.*)$ + +# measure time of runtime and JNIEnv initialization end +init-Debug=monodroid-timing:\s+(?Runtime\.init: end native-to-managed.*)$ +JNI.init-Debug=monodroid-timing:\s+(?JNIEnv\.Initialize end:.*)$ diff --git a/src/Mono.Android/Test/timing-definitions-Release-Aot.txt b/src/Mono.Android/Test/timing-definitions-Release-Aot.txt new file mode 100644 index 00000000000..997b3182cd7 --- /dev/null +++ b/src/Mono.Android/Test/timing-definitions-Release-Aot.txt @@ -0,0 +1,6 @@ +# measure time of last monodroid-timing message appearance +last-Release-Aot=monodroid-timing:\s+(?.*)$ + +# measure time of runtime and JNIEnv initialization end +init-Release-Aot=monodroid-timing:\s+(?Runtime\.init: end native-to-managed.*)$ +JNI.init-Release-Aot=monodroid-timing:\s+(?JNIEnv\.Initialize end:.*)$ diff --git a/src/Mono.Android/Test/timing-definitions-Release.txt b/src/Mono.Android/Test/timing-definitions-Release.txt new file mode 100644 index 00000000000..458b47320db --- /dev/null +++ b/src/Mono.Android/Test/timing-definitions-Release.txt @@ -0,0 +1,6 @@ +# measure time of last monodroid-timing message appearance +last-Release=monodroid-timing:\s+(?.*)$ + +# measure time of runtime and JNIEnv initialization end +init-Release=monodroid-timing:\s+(?Runtime\.init: end native-to-managed.*)$ +JNI.init-Release=monodroid-timing:\s+(?JNIEnv\.Initialize end:.*)$ diff --git a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems index 344b7d95dfa..22e17d970c1 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems +++ b/tests/CodeGen-Binding/Xamarin.Android.JcwGen-Tests/Xamarin.Android.JcwGen-Tests.projitems @@ -5,6 +5,7 @@ Xamarin.Android.JcwGen_Tests xamarin.android.jcwgentests.TestInstrumentation $(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.JcwGen_Tests.xml + $(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt diff --git a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems index 633fcad5d0e..6639fcfe41c 100644 --- a/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems +++ b/tests/locales/Xamarin.Android.Locale-Tests/Xamarin.Android.Locale-Tests.projitems @@ -5,6 +5,7 @@ Xamarin.Android.Locale_Tests xamarin.android.localetests.TestInstrumentation $(MSBuildThisFileDirectory)..\..\..\TestResult-Xamarin.Android.Locale_Tests.xml + $(MSBuildThisFileDirectory)..\..\..\build-tools\scripts\TimingDefinitions.txt From d980ebae64861e9429c0bd72850353c38ac9af04 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 6 Sep 2017 04:33:08 +0900 Subject: [PATCH 19/29] [api-xml-adjuster] Export TOP, JAVA_INTEROP_PATH (#816) Add `$(TOP)`, `$(JAVA_INTEROP_PATH)` to so that we can avoid unnecessary build failures by default. --- build-tools/api-xml-adjuster/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build-tools/api-xml-adjuster/Makefile b/build-tools/api-xml-adjuster/Makefile index 093c5d7334e..a7005bff88a 100644 --- a/build-tools/api-xml-adjuster/Makefile +++ b/build-tools/api-xml-adjuster/Makefile @@ -2,6 +2,9 @@ CONFIGURATION=Debug SHELL = /bin/bash +TOP=../../ +JAVA_INTEROP_PATH=../../external/Java.Interop + ANDROID_SDK_PATH=$(shell find ~/ -maxdepth 1 -name android-sdk-*) DOCS_DIR=~/android-toolchain/docs From 10d1213bff2251f6da7f7935427841dfdde96b9e Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Tue, 5 Sep 2017 20:38:17 +0100 Subject: [PATCH 20/29] [Xamarin.Android.Build.Tasks] Implement Managed Resource Parser (#787) Implement a Managed Resource Parser for DesignTime Builds on Windows, which avoids use of `aapt`. One of our (many) problems in the DesignTime build is the amount of time we need to spend in `aapt`. Our current Resource Designer generator process is as follows. 1. Copy all the resources into one folder. 2. Correct the Casing on those resources so they are lowercase while maintaining a map of the changes we made. 3. Call `aapt` to generate a `R.java` file which contains all the Id's for the required resources. 4. Parse the `R.java` file and create a C# Code Dom to represent the Resource.Designer.cs. Note we also need to convert the lowercased resource back into the case from the app so the C# code will match what the user typed in. 5. Finally write out the `Resource.Designer.cs` So we do a TON of stuff there. For a design time build we don't really need to do all of that stuff. Firstly because its a design time build (not a real one) we don't care about what the values of the ids are. We just need to have a good `Resource.Designer.cs` class. We also don't need to convert the casing back and forth. We can just use the casing the user defines because that is what we normally end up with anyway. We don't need to generate a `R.java` as we can operate on the projects `Resources` folder directly. --- Documentation/build_process.md | 6 + .../Tasks/GenerateResourceDesigner.cs | 18 +- .../AndroidUpdateResourcesTest.cs | 138 ++++++- .../Xamarin.Android.Build.Tests/BuildTest.cs | 1 + .../Utilities/JavaResourceParser.cs | 56 +-- .../Utilities/ManagedResourceParser.cs | 345 ++++++++++++++++++ .../Utilities/ResourceParser.cs | 55 +++ .../Xamarin.Android.Build.Tasks.csproj | 2 + .../Xamarin.Android.Common.targets | 58 ++- 9 files changed, 626 insertions(+), 53 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs diff --git a/Documentation/build_process.md b/Documentation/build_process.md index 6ba90ae3452..88464b8f90c 100644 --- a/Documentation/build_process.md +++ b/Documentation/build_process.md @@ -587,6 +587,12 @@ when packaing Release applications. Added in Xamarin.Android 7.2. +- **AndroidUseManagedDesignTimeResourceGenerator** – A boolean property which + will switch over the design time builds to use the managed resource parser rather + than `aapt`. + + Added in Xamarin.Android 7.3. + ## Binding Project Build Properties The following MSBuild properties are used with diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs index 367d846394f..d5e5b2c057b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesigner.cs @@ -38,6 +38,9 @@ public class GenerateResourceDesigner : Task public ITaskItem[] References { get; set; } + [Required] + public bool UseManagedResourceGenerator { get; set; } + private Dictionary resource_fixup = new Dictionary (StringComparer.OrdinalIgnoreCase); public override bool Execute () @@ -56,10 +59,11 @@ public override bool Execute () Log.LogDebugMessage (" ResourceDirectory: {0}", ResourceDirectory); Log.LogDebugTaskItemsAndLogical (" AdditionalResourceDirectories:", AdditionalResourceDirectories); Log.LogDebugMessage (" IsApplication: {0}", IsApplication); + Log.LogDebugMessage (" UseManagedResourceGenerator: {0}", UseManagedResourceGenerator); Log.LogDebugTaskItemsAndLogical (" Resources:", Resources); Log.LogDebugTaskItemsAndLogical (" References:", References); - if (!File.Exists (JavaResgenInputFile)) + if (!File.Exists (JavaResgenInputFile) && !UseManagedResourceGenerator) return true; // ResourceDirectory may be a relative path, and @@ -89,8 +93,14 @@ public override bool Execute () } // Parse out the resources from the R.java file - JavaResourceParser.Log = Log; - var resources = JavaResourceParser.Parse (JavaResgenInputFile, IsApplication, resource_fixup); + CodeTypeDeclaration resources; + if (UseManagedResourceGenerator) { + var parser = new ManagedResourceParser () { Log = Log }; + resources = parser.Parse (ResourceDirectory, AdditionalResourceDirectories?.Select (x => x.ItemSpec), IsApplication, resource_fixup); + } else { + var parser = new JavaResourceParser () { Log = Log }; + resources = parser.Parse (JavaResgenInputFile, IsApplication, resource_fixup); + } var extension = Path.GetExtension (NetResgenOutputFile); var language = string.Compare (extension, ".fs", StringComparison.OrdinalIgnoreCase) == 0 ? "F#" : CodeDomProvider.GetLanguageFromExtension (extension); @@ -269,7 +279,7 @@ static string NormalizeAlternative (string value) int a = value.IndexOf ('-'); return - JavaResourceParser.GetNestedTypeName (value.Substring (0, (a < 0 || a >= s) ? s : a)).ToLowerInvariant () + + ResourceParser.GetNestedTypeName (value.Substring (0, (a < 0 || a >= s) ? s : a)).ToLowerInvariant () + value.Substring (s); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs index a5254a57b5a..e9e2464fa41 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidUpdateResourcesTest.cs @@ -73,7 +73,7 @@ public void DesignTimeBuild ([Values(false, true)] bool isRelease) new BuildItem.ProjectReference (@"..\Lib1\Lib1.csproj", lib.ProjectName, lib.ProjectGuid), }, }; - + proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "False"); using (var l = CreateDllBuilder (Path.Combine (path, lib.ProjectName), false, false)) { using (var b = CreateApkBuilder (Path.Combine (path, proj.ProjectName), false, false)) { l.Verbosity = LoggerVerbosity.Diagnostic; @@ -430,6 +430,7 @@ public void CheckOldResourceDesignerIsNotUsed (bool isRelease, ProjectLanguage l IsRelease = isRelease, }; proj.SetProperty ("AndroidUseIntermediateDesignerFile", "True"); + proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "False"); using (var b = CreateApkBuilder ("temp/CheckOldResourceDesignerIsNotUsed")) { var designer = Path.Combine ("Resources", "Resource.designer" + proj.Language.DefaultDesignerExtension); if (File.Exists (designer)) @@ -938,5 +939,140 @@ public string GetFoo () { } } } + + [Test] + public void BuildAppWithManagedResourceParser() + { + var path = Path.Combine ("temp", "BuildAppWithManagedResourceParser"); + var appProj = new XamarinAndroidApplicationProject () { + IsRelease = true, + ProjectName = "App1", + }; + appProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + using (var appBuilder = CreateApkBuilder (Path.Combine (path, appProj.ProjectName))) { + appBuilder.Verbosity = LoggerVerbosity.Diagnostic; + appBuilder.Target = "Compile"; + Assert.IsTrue (appBuilder.Build (appProj, parameters: new string[] { "DesignTimeBuild=true"} ), + "DesignTime Application Build should have succeeded."); + Assert.IsFalse (appProj.CreateBuildOutput (appBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should have run."); + var designerFile = Path.Combine (Root, path, appProj.ProjectName, appProj.IntermediateOutputPath, "designtime", "Resource.Designer.cs"); + FileAssert.Exists (designerFile, $"'{designerFile}' should have been created."); + + var designerContents = File.ReadAllText (designerFile); + StringAssert.Contains ("hello", designerContents, $"{designerFile} should contain Resources.Strings.hello"); + StringAssert.Contains ("app_name", designerContents, $"{designerFile} should contain Resources.Strings.app_name"); + StringAssert.Contains ("myButton", designerContents, $"{designerFile} should contain Resources.Id.myButton"); + StringAssert.Contains ("Icon", designerContents, $"{designerFile} should contain Resources.Drawable.Icon"); + StringAssert.Contains ("Main", designerContents, $"{designerFile} should contain Resources.Layout.Main"); + appBuilder.Target = "SignAndroidPackage"; + Assert.IsTrue (appBuilder.Build (appProj), + "Normal Application Build should have succeeded."); + Assert.IsTrue (appProj.CreateBuildOutput (appBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should not have run."); + + Assert.IsTrue (appBuilder.Clean (appProj), "Clean should have succeeded"); + Assert.IsFalse (File.Exists (designerFile), $"'{designerFile}' should have been cleaned."); + + } + } + + [Test] + public void BuildAppWithManagedResourceParserAndLibraries () + { + int maxBuildTimeMs = 5000; + var path = Path.Combine ("temp", "BuildAppWithManagedResourceParserAndLibraries"); + var theme = new AndroidItem.AndroidResource ("Resources\\values\\Theme.xml") { + TextContent = () => @" + + #ffffffff + #ffffffff +", + }; + var libProj = new XamarinAndroidLibraryProject () { + IsRelease = true, + ProjectName = "Lib1", + AndroidResources = { + theme, + }, + }; + libProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + var appProj = new XamarinAndroidApplicationProject () { + IsRelease = true, + ProjectName = "App1", + References = { + new BuildItem.ProjectReference (@"..\Lib1\Lib1.csproj", libProj.ProjectName, libProj.ProjectGuid), + }, + Packages = { + KnownPackages.SupportMediaCompat_25_4_0_1, + KnownPackages.SupportFragment_25_4_0_1, + KnownPackages.SupportCoreUtils_25_4_0_1, + KnownPackages.SupportCoreUI_25_4_0_1, + KnownPackages.SupportCompat_25_4_0_1, + KnownPackages.AndroidSupportV4_25_4_0_1, + KnownPackages.SupportV7AppCompat_25_4_0_1, + }, + }; + appProj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "True"); + using (var libBuilder = CreateDllBuilder (Path.Combine (path, libProj.ProjectName), false, false)) { + libBuilder.Verbosity = LoggerVerbosity.Diagnostic; + using (var appBuilder = CreateApkBuilder (Path.Combine (path, appProj.ProjectName), false, false)) { + appBuilder.Verbosity = LoggerVerbosity.Diagnostic; + libBuilder.Target = "Compile"; + Assert.IsTrue (libBuilder.Build (libProj, parameters: new string [] { "DesignTimeBuild=true" }), "Library project should have built"); + Assert.LessOrEqual (libBuilder.LastBuildTime.TotalMilliseconds, maxBuildTimeMs, "DesingTime build should be less than 5 seconds."); + Assert.IsFalse (libProj.CreateBuildOutput (libBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should have run."); + appBuilder.Target = "Compile"; + Assert.IsTrue (appBuilder.Build (appProj, parameters: new string [] { "DesignTimeBuild=true" }), "Library project should have built"); + Assert.LessOrEqual (appBuilder.LastBuildTime.TotalMilliseconds, maxBuildTimeMs, "DesingTime build should be less than 5 seconds."); + Assert.IsFalse (appProj.CreateBuildOutput (appBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should have run."); + var designerFile = Path.Combine (Root, path, appProj.ProjectName, appProj.IntermediateOutputPath, "designtime", "Resource.Designer.cs"); + FileAssert.Exists (designerFile, $"'{designerFile}' should have been created."); + + var designerContents = File.ReadAllText (designerFile); + StringAssert.Contains ("hello", designerContents, $"{designerFile} should contain Resources.Strings.hello"); + StringAssert.Contains ("app_name", designerContents, $"{designerFile} should contain Resources.Strings.app_name"); + StringAssert.Contains ("myButton", designerContents, $"{designerFile} should contain Resources.Id.myButton"); + StringAssert.Contains ("Icon", designerContents, $"{designerFile} should contain Resources.Drawable.Icon"); + StringAssert.Contains ("Main", designerContents, $"{designerFile} should contain Resources.Layout.Main"); + StringAssert.Contains ("material_grey_50", designerContents, $"{designerFile} should contain Resources.Color.material_grey_50"); + StringAssert.DoesNotContain ("theme_devicedefault_background", designerContents, $"{designerFile} should not contain Resources.Color.theme_devicedefault_background"); + libBuilder.Target = "Build"; + Assert.IsTrue (libBuilder.Build (libProj), "Library project should have built"); + Assert.IsTrue (libProj.CreateBuildOutput (libBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should not have run."); + appBuilder.Target = "Compile"; + Assert.IsTrue (appBuilder.Build (appProj, parameters: new string [] { "DesignTimeBuild=true" }), "App project should have built"); + Assert.LessOrEqual (appBuilder.LastBuildTime.TotalMilliseconds, maxBuildTimeMs, "DesingTime build should be less than 5 seconds."); + Assert.IsFalse (appProj.CreateBuildOutput (appBuilder).IsTargetSkipped ("_ManagedUpdateAndroidResgen"), + "Target '_ManagedUpdateAndroidResgen' should have run."); + FileAssert.Exists (designerFile, $"'{designerFile}' should have been created."); + + designerContents = File.ReadAllText (designerFile); + StringAssert.Contains ("hello", designerContents, $"{designerFile} should contain Resources.Strings.hello"); + StringAssert.Contains ("app_name", designerContents, $"{designerFile} should contain Resources.Strings.app_name"); + StringAssert.Contains ("myButton", designerContents, $"{designerFile} should contain Resources.Id.myButton"); + StringAssert.Contains ("Icon", designerContents, $"{designerFile} should contain Resources.Drawable.Icon"); + StringAssert.Contains ("Main", designerContents, $"{designerFile} should contain Resources.Layout.Main"); + StringAssert.Contains ("material_grey_50", designerContents, $"{designerFile} should contain Resources.Color.material_grey_50"); + StringAssert.Contains ("theme_devicedefault_background", designerContents, $"{designerFile} should contain Resources.Color.theme_devicedefault_background"); + StringAssert.Contains ("SomeColor", designerContents, $"{designerFile} should contain Resources.Color.SomeColor"); + + appBuilder.Target = "SignAndroidPackage"; + Assert.IsTrue (appBuilder.Build (appProj), "App project should have built"); + + + Assert.IsTrue (appBuilder.Clean (appProj), "Clean should have succeeded"); + Assert.IsFalse (File.Exists (designerFile), $"'{designerFile}' should have been cleaned."); + designerFile = Path.Combine (Root, path, libProj.ProjectName, libProj.IntermediateOutputPath, "designtime", "Resource.Designer.cs"); + Assert.IsTrue (libBuilder.Clean (libProj), "Clean should have succeeded"); + Assert.IsFalse (File.Exists (designerFile), $"'{designerFile}' should have been cleaned."); + + + } + } + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index b8edb54f55a..a4c5a382cf6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -1760,6 +1760,7 @@ public void BuildInDesignTimeMode () var proj = new XamarinAndroidApplicationProject () { IsRelease = true, }; + proj.SetProperty ("AndroidUseManagedDesignTimeResourceGenerator", "False"); using (var builder = CreateApkBuilder (Path.Combine ("temp", TestContext.CurrentContext.Test.Name), false ,false)) { builder.Verbosity = LoggerVerbosity.Diagnostic; builder.Target = "UpdateAndroidResources"; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs index 766dfbf8980..1d8b2349ed5 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/JavaResourceParser.cs @@ -9,11 +9,9 @@ namespace Xamarin.Android.Tasks { - class JavaResourceParser + class JavaResourceParser : ResourceParser { - public static TaskLoggingHelper Log { get; set; } - - public static CodeTypeDeclaration Parse (string file, bool isApp, Dictionary resourceMap) + public CodeTypeDeclaration Parse (string file, bool isApp, Dictionary resourceMap) { if (!File.Exists (file)) throw new InvalidOperationException ("Specified Java resource file was not found: " + file); @@ -49,18 +47,22 @@ static KeyValuePair, CodeTypeDeclaration>>> Parser = new List, CodeTypeDeclaration>>> () { + List, CodeTypeDeclaration>>> Parser; + + public JavaResourceParser () + { + Parser = new List, CodeTypeDeclaration>>> () { Parse ("^public final class R {", (m, app, _, map) => { var decl = new CodeTypeDeclaration ("Resource") { IsPartial = true, }; var asm = Assembly.GetExecutingAssembly().GetName(); - var codeAttrDecl = + var codeAttrDecl = new CodeAttributeDeclaration("System.CodeDom.Compiler.GeneratedCodeAttribute", - new CodeAttributeArgument( + new CodeAttributeArgument( new CodePrimitiveExpression(asm.Name)), - new CodeAttributeArgument( + new CodeAttributeArgument( new CodePrimitiveExpression(asm.Version.ToString())) ); decl.CustomAttributes.Add(codeAttrDecl); @@ -116,44 +118,6 @@ static KeyValuePair map) - { - string mappedValue; - string key = string.Format ("{0}{1}{2}", type, Path.DirectorySeparatorChar, name).ToLowerInvariant (); - - if (map.TryGetValue (key, out mappedValue)) { - Log.LogMessage (" - Remapping resource: {0}.{1} -> {2}", type, name, mappedValue); - return mappedValue.Substring (mappedValue.LastIndexOf (Path.DirectorySeparatorChar) + 1); - } - - Log.LogMessage (" - Not remapping resource: {0}.{1}", type, name); - - return name; - } - } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs new file mode 100644 index 00000000000..a106936282d --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManagedResourceParser.cs @@ -0,0 +1,345 @@ +using System; +using System.CodeDom; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml; + +namespace Xamarin.Android.Tasks +{ + class ManagedResourceParser : ResourceParser + { + CodeTypeDeclaration resources; + CodeTypeDeclaration layout, ids, drawable, strings, colors, dimension, raw, animation, attrib, boolean, ints, styleable, style, arrays; + Dictionary map; + + void SortMembers (CodeTypeDeclaration decl) + { + CodeTypeMember [] members = new CodeTypeMember [decl.Members.Count]; + decl.Members.CopyTo (members, 0); + decl.Members.Clear (); + Array.Sort (members, (x, y) => string.Compare (x.Name, y.Name, StringComparison.OrdinalIgnoreCase)); + decl.Members.AddRange (members); + } + + public CodeTypeDeclaration Parse (string resourceDirectory, IEnumerable additionalResourceDirectories, bool isApp, Dictionary resourceMap) + { + if (!Directory.Exists (resourceDirectory)) + throw new ArgumentException ("Specified resource directory was not found: " + resourceDirectory); + + map = resourceMap ?? new Dictionary (); + resources = CreateResourceClass (); + animation = CreateClass ("Animation"); + arrays = CreateClass ("Array"); + attrib = CreateClass ("Attribute"); + boolean = CreateClass ("Boolean"); + layout = CreateClass ("Layout"); + ids = CreateClass ("Id"); + ints = CreateClass ("Integer"); + drawable = CreateClass ("Drawable"); + strings = CreateClass ("String"); + colors = CreateClass ("Color"); + dimension = CreateClass ("Dimension"); + raw = CreateClass ("Raw"); + styleable = CreateClass ("Styleable"); + style = CreateClass ("Style"); + + foreach (var dir in Directory.GetDirectories (resourceDirectory, "*", SearchOption.TopDirectoryOnly)) { + foreach (var file in Directory.GetFiles (dir, "*.*", SearchOption.AllDirectories)) { + ProcessResourceFile (file); + } + } + if (additionalResourceDirectories != null) { + foreach (var dir in additionalResourceDirectories) { + foreach (var file in Directory.GetFiles (dir, "*.*", SearchOption.AllDirectories)) { + ProcessResourceFile (file); + } + } + } + + SortMembers (animation); + SortMembers (ids); + SortMembers (attrib); + SortMembers (arrays); + SortMembers (boolean); + SortMembers (colors); + SortMembers (dimension); + SortMembers (drawable); + SortMembers (ints); + SortMembers (layout); + SortMembers (raw); + SortMembers (strings); + SortMembers (style); + SortMembers (styleable); + + + if (animation.Members.Count > 1) + resources.Members.Add (animation); + if (arrays.Members.Count > 1) + resources.Members.Add (arrays); + if (attrib.Members.Count > 1) + resources.Members.Add (attrib); + if (boolean.Members.Count > 1) + resources.Members.Add (boolean); + if (colors.Members.Count > 1) + resources.Members.Add (colors); + if (dimension.Members.Count > 1) + resources.Members.Add (dimension); + if (drawable.Members.Count > 1) + resources.Members.Add (drawable); + if (ids.Members.Count > 1) + resources.Members.Add (ids); + if (ints.Members.Count > 1) + resources.Members.Add (ints); + if (layout.Members.Count > 1) + resources.Members.Add (layout); + if (raw.Members.Count > 1) + resources.Members.Add (raw); + if (strings.Members.Count > 1) + resources.Members.Add (strings); + if (style.Members.Count > 1) + resources.Members.Add (style); + if (styleable.Members.Count > 1) + resources.Members.Add (styleable); + + return resources; + } + + void ProcessResourceFile (string file) + { + var fileName = Path.GetFileNameWithoutExtension (file); + if (string.IsNullOrEmpty (fileName)) + return; + if (fileName.EndsWith (".9", StringComparison.OrdinalIgnoreCase)) + fileName = Path.GetFileNameWithoutExtension (fileName); + var path = Directory.GetParent (file).Name; + var ext = Path.GetExtension (file); + switch (ext) { + case ".xml": + case ".axml": + if (string.Compare (path, "raw", StringComparison.OrdinalIgnoreCase) == 0) + goto default; + ProcessXmlFile (file); + break; + default: + break; + } + CreateResourceField (path, fileName); + } + + CodeTypeDeclaration CreateResourceClass () + { + var decl = new CodeTypeDeclaration ("Resource") { + IsPartial = true, + }; + var asm = Assembly.GetExecutingAssembly ().GetName (); + var codeAttrDecl = + new CodeAttributeDeclaration ("System.CodeDom.Compiler.GeneratedCodeAttribute", + new CodeAttributeArgument ( + new CodePrimitiveExpression (asm.Name)), + new CodeAttributeArgument ( + new CodePrimitiveExpression (asm.Version.ToString ())) + ); + decl.CustomAttributes.Add (codeAttrDecl); + return decl; + } + + CodeTypeDeclaration CreateClass (string type) + { + var t = new CodeTypeDeclaration (ResourceParser.GetNestedTypeName (type)) { + IsPartial = true, + TypeAttributes = TypeAttributes.Public, + }; + t.Members.Add (new CodeConstructor () { + Attributes = MemberAttributes.Private, + }); + return t; + } + + void CreateField (CodeTypeDeclaration parentType, string name, Type type) + { + var f = new CodeMemberField (type, name) { + // pity I can't make the member readonly... + Attributes = MemberAttributes.Public | MemberAttributes.Static, + }; + parentType.Members.Add (f); + } + + void CreateIntField (CodeTypeDeclaration parentType, string name) + { + string mappedName = GetResourceName (parentType.Name, name, map); + if (parentType.Members.OfType ().Any (x => string.Compare (x.Name, mappedName, StringComparison.OrdinalIgnoreCase) == 0)) + return; + var f = new CodeMemberField (typeof (int), mappedName) { + // pity I can't make the member readonly... + Attributes = MemberAttributes.Static | MemberAttributes.Public, + InitExpression = new CodePrimitiveExpression (0), + Comments = { + new CodeCommentStatement ("aapt resource value: 0"), + }, + }; + parentType.Members.Add (f); + } + + void CreateIntArrayField (CodeTypeDeclaration parentType, string name, int count) + { + string mappedName = GetResourceName (parentType.Name, name, map); + if (parentType.Members.OfType ().Any (x => string.Compare (x.Name, mappedName, StringComparison.OrdinalIgnoreCase) == 0)) + return; + var f = new CodeMemberField (typeof (int []), name) { + // pity I can't make the member readonly... + Attributes = MemberAttributes.Public | MemberAttributes.Static, + }; + CodeArrayCreateExpression c = (CodeArrayCreateExpression)f.InitExpression; + if (c == null) { + f.InitExpression = c = new CodeArrayCreateExpression (typeof (int [])); + } + for (int i = 0; i < count; i++) + c.Initializers.Add (new CodePrimitiveExpression (0)); + + parentType.Members.Add (f); + } + + HashSet resourceNamesToUseDirectly = new HashSet () { + "integer-array", + "string-array", + "declare-styleable", + "add-resource", + }; + + void CreateResourceField (string root, string fieldName, XmlReader element = null) + { + var i = root.IndexOf ('-'); + var item = i < 0 ? root : root.Substring (0, i); + item = resourceNamesToUseDirectly.Contains (root) ? root : item; + switch (item.ToLower ()) { + case "bool": + CreateIntField (boolean, fieldName); + break; + case "color": + CreateIntField (colors, fieldName); + break; + case "drawable": + CreateIntField (drawable, fieldName); + break; + case "dimen": + case "fraction": + CreateIntField (dimension, fieldName); + break; + case "integer": + CreateIntField (ints, fieldName); + break; + case "anim": + CreateIntField (animation, fieldName); + break; + case "attr": + CreateIntField (attrib, fieldName); + break; + case "layout": + CreateIntField (layout, fieldName); + break; + case "raw": + CreateIntField (raw, fieldName); + break; + case "string": + CreateIntField (strings, fieldName); + break; + case "enum": + case "flag": + case "id": + CreateIntField (ids, fieldName); + break; + case "integer-array": + case "string-array": + CreateIntField (arrays, fieldName); + break; + case "configVarying": + case "add-resource": + case "declare-styleable": + ProcessStyleable (element); + break; + case "style": + CreateIntField (style, fieldName.Replace (".", "_")); + break; + default: + break; + } + } + + void ProcessStyleable (XmlReader reader) + { + string topName = null; + int fieldCount = 0; + while (reader.Read ()) { + if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) + continue; + string name = null; + if (string.IsNullOrEmpty (topName)) { + if (reader.HasAttributes) { + while (reader.MoveToNextAttribute ()) { + if (reader.Name.Replace ("android:", "") == "name") + topName = reader.Value; + } + } + } + if (!reader.IsStartElement () || reader.LocalName == "declare-styleable") + continue; + if (reader.HasAttributes) { + while (reader.MoveToNextAttribute ()) { + if (reader.Name.Replace ("android:", "") == "name") + name = reader.Value; + } + } + reader.MoveToElement (); + if (reader.LocalName == "attr") { + CreateIntField (styleable, $"{topName}_{name.Replace (":", "_")}"); + if (!name.StartsWith ("android:", StringComparison.OrdinalIgnoreCase)) + CreateIntField (attrib, name); + fieldCount++; + } else { + if (name != null) + CreateIntField (ids, $"{name.Replace (":", "_")}"); + } + } + CreateIntArrayField (styleable, topName, fieldCount); + } + + void ProcessXmlFile (string file) + { + using (var reader = XmlReader.Create (file)) { + while (reader.Read ()) { + if (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.Comment) + continue; + if (reader.IsStartElement ()) { + var elementName = reader.Name; + if (reader.HasAttributes) { + string name = null; + string type = null; + string id = null; + while (reader.MoveToNextAttribute ()) { + if (reader.LocalName == "name") + name = reader.Value; + if (reader.LocalName == "type") + type = reader.Value; + if (reader.LocalName == "id") + id = reader.Value.Replace ("@+id/", "").Replace ("@id/", ""); ; + } + if (name?.Contains ("android:") ?? false) + continue; + if (id?.Contains ("android:") ?? false) + continue; + // Move the reader back to the element node. + reader.MoveToElement (); + if (!string.IsNullOrEmpty (name)) + CreateResourceField (type ?? elementName, name, reader.ReadSubtree ()); + if (!string.IsNullOrEmpty (id)) { + CreateIntField (ids, id); + } + } + } + } + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs new file mode 100644 index 00000000000..f98053bae82 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ResourceParser.cs @@ -0,0 +1,55 @@ +using System; +using System.CodeDom; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using Microsoft.Build.Utilities; + +namespace Xamarin.Android.Tasks +{ + class ResourceParser + { + public TaskLoggingHelper Log { get; set; } + + internal int ToInt32 (string value, int @base) + { + try { + return Convert.ToInt32 (value, @base); + } catch (Exception e) { + throw new NotSupportedException ( + string.Format ("Could not convert value '{0}' (base '{1}') into an Int32.", + value, @base), + e); + } + } + + internal static string GetNestedTypeName (string name) + { + switch (name) { + case "anim": return "Animation"; + case "attr": return "Attribute"; + case "bool": return "Boolean"; + case "dimen": return "Dimension"; + default: return char.ToUpperInvariant (name[0]) + name.Substring (1); + } + } + + internal string GetResourceName (string type, string name, Dictionary map) + { + string mappedValue; + string key = string.Format ("{0}{1}{2}", type, Path.DirectorySeparatorChar, name).ToLowerInvariant (); + + if (map.TryGetValue (key, out mappedValue)) { + Log.LogDebugMessage (" - Remapping resource: {0}.{1} -> {2}", type, name, mappedValue); + return mappedValue.Substring (mappedValue.LastIndexOf (Path.DirectorySeparatorChar) + 1); + } + + Log.LogDebugMessage (" - Not remapping resource: {0}.{1}", type, name); + + return name; + } + + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index c2425aa89e4..267a0316751 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -102,6 +102,8 @@ + + diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 08c3fadcac2..40637cf82a9 100755 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -993,6 +993,9 @@ because xbuild doesn't support framework reference assemblies. <_AndroidResourceDesignerFile Condition=" '$(AndroidUseIntermediateDesignerFile)' != 'True' ">$(AndroidResgenFile) <_AndroidStaticResourcesFlag>$(IntermediateOutputPath)static.flag <_AndroidResourcesCacheFile>$(IntermediateOutputPath)mergeresources.cache + True + <_AndroidDesignTimeResDirIntermediate>$(IntermediateOutputPath)designtime\ + <_AndroidManagedResourceDesignerFile>$(_AndroidDesignTimeResDirIntermediate)$(_AndroidResourceDesigner) @@ -1036,11 +1039,60 @@ because xbuild doesn't support framework reference assemblies. Overwrite="true"/> + + + + True + + + + + False + + + + + + + + + + + + + + + + + + - + + + + @@ -2473,6 +2526,7 @@ because xbuild doesn't support framework reference assemblies. + From 7ad9c59216b6ef6f6cf2a9e785d09587ab09e187 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Wed, 6 Sep 2017 04:43:08 +0900 Subject: [PATCH 21/29] [Xamarin.Android.Build.Tasks-Tests] Fix path to msbuild on Linux (#809) Keep in mind that there is no `/Library/Frameworks/Mono.framework` outside macOS. --- .../Tests/Xamarin.ProjectTools/Common/Builder.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs index 851ae7d271d..81add458978 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/Builder.cs @@ -11,6 +11,7 @@ namespace Xamarin.ProjectTools public class Builder : IDisposable { const string fixed_osx_xbuild_path = "/Library/Frameworks/Mono.framework/Commands"; + const string fixed_linux_xbuild_path = "/usr/bin"; const string xbuildapp = "xbuild"; const string msbuildapp = "msbuild"; string msbuildExe; @@ -26,9 +27,10 @@ public class Builder : IDisposable string GetUnixBuildExe () { RunningMSBuild = false; - string path = Path.Combine (fixed_osx_xbuild_path, xbuildapp); + var tooldir = Directory.Exists (fixed_osx_xbuild_path) ? fixed_osx_xbuild_path : fixed_linux_xbuild_path; + string path = Path.Combine (tooldir, xbuildapp); if (!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("USE_MSBUILD"))) { - path = Path.Combine (fixed_osx_xbuild_path, msbuildapp); + path = Path.Combine (tooldir, msbuildapp); RunningMSBuild = true; } return File.Exists (path) ? path : msbuildapp; From b05b5b6e612ff6941500f27661ec145246c47367 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 5 Sep 2017 15:01:27 -0500 Subject: [PATCH 22/29] [setup-windows] Fix for VS 2017 and MSBuild 15+ (#811) When building `HelloWorld.csproj`, my machine is loading reference assemblies from: ReferenceAssemblyPaths: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v1.0\ This is different from what `setup-windows.exe` is making a link for. So if I attempt to build `HelloWorld.csproj` for API 26 / `$(TargetFrameworkVersion)` v8.0, it fails because the framework does not exist on my system. It turns out this is happening because I am using MSBuild 15.0 from my VS install, instead of the .NET framework version of MSBuild. The fix here is to create an additional file link for VS 2017 if `VSINSTALLDIR` is set. I also streamlined the `Uninstall` method so it takes in a list of directories. --- Documentation/UsingJenkinsBuildArtifacts.md | 1 + tools/setup-windows/SetupWindows.cs | 54 ++++++++++++--------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Documentation/UsingJenkinsBuildArtifacts.md b/Documentation/UsingJenkinsBuildArtifacts.md index 9517f6fbf04..22f6425bbd0 100644 --- a/Documentation/UsingJenkinsBuildArtifacts.md +++ b/Documentation/UsingJenkinsBuildArtifacts.md @@ -111,6 +111,7 @@ Administrator-elevated **Developer Command Prompt for VS 2017** window: Within the elevated command prompt, execute the `setup-windows.exe` program: > C:\xa-sdk\oss-xamarin.android_v7.4.99.60_Darwin-x86_64_master_4f3d604\bin\Debug\bin\setup-windows.exe + Executing: MKLINK /D "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid" "C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\lib\xamarin.android\xbuild-frameworks\MonoAndroid" Executing: MKLINK /D "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid" "C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\lib\xamarin.android\xbuild-frameworks\MonoAndroid" Executing: MKLINK /D "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Xamarin\Android" "C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\lib\xamarin.android\xbuild\Xamarin\Android" Success! diff --git a/tools/setup-windows/SetupWindows.cs b/tools/setup-windows/SetupWindows.cs index 67920d1025a..574cd8c41f9 100644 --- a/tools/setup-windows/SetupWindows.cs +++ b/tools/setup-windows/SetupWindows.cs @@ -31,14 +31,18 @@ public static int Main (string [] args) var prefix = Path.GetDirectoryName (appDir); var hash = XAZipFolderNameToHash (Path.GetFileName (Path.GetDirectoryName (Path.GetDirectoryName (prefix)))); + var refAssembliesDirectories = new List (); var progFiles = Environment.GetEnvironmentVariable ("ProgramFiles(x86)"); var vsInstall = Environment.GetEnvironmentVariable ("VSINSTALLDIR"); if (string.IsNullOrEmpty (vsInstall)) { vsInstall = progFiles; + } else { + refAssembliesDirectories.Add (Path.Combine (vsInstall, "Common7", "IDE", "ReferenceAssemblies", "Microsoft", "Framework", "MonoAndroid")); } + refAssembliesDirectories.Add (Path.Combine (progFiles, "Reference Assemblies", "Microsoft", "Framework", "MonoAndroid")); + var msbuildTargets = Path.Combine (vsInstall, "MSBuild", "Xamarin", "Android"); var newTargets = Path.Combine (prefix, "lib", "xamarin.android", "xbuild", "Xamarin", "Android"); - var refAssemblies = Path.Combine (progFiles, "Reference Assemblies", "Microsoft", "Framework", "MonoAndroid"); var newAssemblies = Path.Combine (prefix, "lib", "xamarin.android", "xbuild-frameworks", "MonoAndroid"); if (Path.DirectorySeparatorChar != '\\') { @@ -47,29 +51,35 @@ public static int Main (string [] args) } if (args.Length == 0 || args.Any (v => string.Equals (v, "install", StringComparison.OrdinalIgnoreCase) || string.Equals (v, "/install", StringComparison.OrdinalIgnoreCase))) { - return Install (msbuildTargets, newTargets, refAssemblies, newAssemblies, hash); + return Install (hash, msbuildTargets, newTargets, refAssembliesDirectories, newAssemblies); } if (args.Any (v => string.Equals (v, "uninstall", StringComparison.OrdinalIgnoreCase) || string.Equals (v, "/uninstall", StringComparison.OrdinalIgnoreCase))) { - return Uninstall (msbuildTargets, refAssemblies, hash); + var directories = new List (refAssembliesDirectories); + directories.Add (msbuildTargets); + return Uninstall (hash, directories); } Console.Error.WriteLine ($"{AppName}: Invalid command `{string.Join (" ", args)}`."); return 1; } - static int Install (string msbuildTargets, string newTargets, string refAssemblies, string newAssemblies, string hash) + static int Install (string hash, string msbuildTargets, string newTargets, List refAssembliesDirectories, string newAssemblies) { - var backupAssemblies = GetNewBackupName (refAssemblies, hash); - var backupTargets = GetNewBackupName (msbuildTargets, hash); try { - Directory.CreateDirectory (Path.GetDirectoryName (refAssemblies)); - Directory.CreateDirectory (Path.GetDirectoryName (msbuildTargets)); + foreach (var refAssemblies in refAssembliesDirectories) { + var backupAssemblies = GetNewBackupName (refAssemblies, hash); + Directory.CreateDirectory (Path.GetDirectoryName (refAssemblies)); + if (!CreateSymbolicLink (refAssemblies, newAssemblies, backupAssemblies)) + return 1; + } - if (CreateSymbolicLink (refAssemblies, newAssemblies, backupAssemblies) && - CreateSymbolicLink (msbuildTargets, newTargets, backupTargets)) { - Console.WriteLine ("Success!"); - return 0; + var backupTargets = GetNewBackupName (msbuildTargets, hash); + Directory.CreateDirectory (Path.GetDirectoryName (msbuildTargets)); + if (!CreateSymbolicLink (msbuildTargets, newTargets, backupTargets)) { + return 1; } - return 1; + + Console.WriteLine ("Success!"); + return 0; } catch (UnauthorizedAccessException e) { Console.Error.WriteLine ($"{AppName}: {e.Message}"); @@ -130,18 +140,14 @@ static bool CreateSymbolicLink (string source, string target, string backup) return true; } - static int Uninstall (string msbuildTargets, string refAssemblies, string hash) + static int Uninstall (string hash, List directories) { - var backupTargets = GetExistingBackupName (msbuildTargets, hash); - var backupAssemblies = GetExistingBackupName (refAssemblies, hash); - - Directory.Delete (msbuildTargets); - if (backupTargets != null && Directory.Exists (backupTargets)) { - Directory.Move (backupTargets, msbuildTargets); - } - Directory.Delete (refAssemblies); - if (backupAssemblies != null && Directory.Exists (backupAssemblies)) { - Directory.Move (backupAssemblies, refAssemblies); + foreach (var directory in directories) { + var backup = GetExistingBackupName (directory, hash); + Directory.Delete (directory); + if (backup != null && Directory.Exists (backup)) { + Directory.Move (backup, directory); + } } return 0; } From a2c173da012f492a2285c1f4cc97c5b5172726df Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 5 Sep 2017 15:40:23 -0400 Subject: [PATCH 23/29] [docs] Fix Markdown formatting, correct version. `$(AndroidUseManagedDesignTimeResourceGenerator)` is being added to Xamarin.Android v8.1, not v7.3. --- Documentation/build_process.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/build_process.md b/Documentation/build_process.md index 88464b8f90c..1229ef002ad 100644 --- a/Documentation/build_process.md +++ b/Documentation/build_process.md @@ -588,10 +588,10 @@ when packaing Release applications. Added in Xamarin.Android 7.2. - **AndroidUseManagedDesignTimeResourceGenerator** – A boolean property which - will switch over the design time builds to use the managed resource parser rather - than `aapt`. + will switch over the design time builds to use the managed resource parser rather + than `aapt`. - Added in Xamarin.Android 7.3. + Added in Xamarin.Android 8.1. ## Binding Project Build Properties From 5ce9f3cbc6ab57045909f8ed7969743491e256a9 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 5 Sep 2017 16:04:49 -0400 Subject: [PATCH 24/29] [docs] Fix `$(AndroidErrorOnCustomJavaObject)` supported version --- Documentation/build_process.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/build_process.md b/Documentation/build_process.md index 1229ef002ad..68abc6a7ad1 100644 --- a/Documentation/build_process.md +++ b/Documentation/build_process.md @@ -234,7 +234,7 @@ when packaing Release applications. When True, such types will generate an XA4212 error, otherwise a XA4212 warning will be generated. - Support for this property was added in Xamarin.Android 7.6. + Support for this property was added in Xamarin.Android 8.1. This property is `True` by default. From e932106c643ad965b98f78cef5d4685c61b65d13 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Tue, 5 Sep 2017 17:12:52 -0400 Subject: [PATCH 25/29] [bundle] Create the bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All builds after [b28fbfc0][b587] have [taken over 5 hours to build][trends]! [b587]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/587/ [trends]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android/buildTimeTrend Build times are now taking 5+ hours because the mono bundle is no longer being used. The mono bundle is no longer being used because the mono bundle is no longer being *created* (from b28fbfc0 build log): Building target "Build" in project "…/xamarin-android/build-tools/bundle/bundle.mdproj" ("…/xamarin-android/build-tools/libzip-windows/libzip-windows.targets"). Target Build skipped due to false condition: '$(HostOS)' == 'Windows' Done building target "Build" in project "…/xamarin-android/build-tools/bundle/bundle.mdproj" ("…/xamarin-android/build-tools/libzip-windows/libzip-windows.targets"). Done building project "…/xamarin-android/build-tools/bundle/bundle.mdproj". The bundle is no longer being created because of commit 6a3f76ea: because `bundle.targets` has an `` for `libzip-windows.targets`, and `libzip-windows.targets` now has its own `Build` target (courtesy 6a3f76ea), the `Build` target from `libzip-windows.targets` *replaces* the expected `Build` target for `bundle.mdproj`/`bundle.targets`, and nothing works as expected. `bundle.targets` doesn't need to import `libzip-windows.targets` anymore -- `libzip-windows.targets` has been empty since 97f08f78 -- so remove the no-longer-necessary `` to restore the normal `Build` target, which will allow `CreateBundle` to actually execute! --- build-tools/bundle/bundle.targets | 1 - 1 file changed, 1 deletion(-) diff --git a/build-tools/bundle/bundle.targets b/build-tools/bundle/bundle.targets index 3bc6b93b559..20ed8f4fb6d 100644 --- a/build-tools/bundle/bundle.targets +++ b/build-tools/bundle/bundle.targets @@ -7,7 +7,6 @@ - From 5edd8af8c127dfc5a13add118c889bac7e4b2a06 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 6 Sep 2017 04:26:29 +0200 Subject: [PATCH 26/29] [monodroid] NetworkInterface fixes (#789) Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=59045 When caching a reference to a Java class one must ensure that the reference is a global one or it will be invalidated on transition to the Java runtime. `JNIEnv::FindClass()` returns a local one, so we need to explicitly call `JNIEnv::NewGlobalRef()` in order to prevent invalidation. Fix reading messages from netlink socket on some emulators. Previously, the buffer we used was sometimes too small and messages were truncated and interpreted incorrectly. Buffer now is dynamically allocated and its size equals the host CPU's page size. This is enough to read the messages we care about. Fix faulty test which didn't take into account link scope for IPv6 addresses. --- .../Test/System.Net/NetworkInterfaces.cs | 40 ++- src/monodroid/jni/monodroid-networkinfo.c | 1 + src/monodroid/jni/xamarin_getifaddrs.c | 262 +++++++++++++++--- 3 files changed, 260 insertions(+), 43 deletions(-) diff --git a/src/Mono.Android/Test/System.Net/NetworkInterfaces.cs b/src/Mono.Android/Test/System.Net/NetworkInterfaces.cs index 1372ddb0789..c4d8d5eef62 100644 --- a/src/Mono.Android/Test/System.Net/NetworkInterfaces.cs +++ b/src/Mono.Android/Test/System.Net/NetworkInterfaces.cs @@ -24,7 +24,7 @@ sealed class InterfaceInfo public override string ToString () { - return string.Format ("[InterfaceInfo: Name={0}, IsLoopback={1}, IsUp={2}, HardwareAddress={3}, Addresses={4}]", Name, IsLoopback, IsUp, HardwareAddress, Addresses); + return string.Format ("[InterfaceInfo: Name={0}, IsLoopback={1}, IsUp={2}, HardwareAddress={3}, Addresses={4}]", Name, IsLoopback, IsUp, HardwareAddressToString (), AddressesToString ()); } public override bool Equals (object obj) @@ -45,6 +45,26 @@ public override bool Equals (object obj) AddressesAreEqual (Addresses, other.Addresses); } + string HardwareAddressToString () + { + if (HardwareAddress == null || HardwareAddress.Length == 0) + return "<>"; + var ret = new List (); + foreach (byte b in HardwareAddress) + ret.Add (b.ToString ("X02")); + return "<" + String.Join (":", ret) + ">"; + } + + string AddressesToString () + { + if (Addresses == null || Addresses.Count == 0) + return "<>"; + var ret = new List (); + foreach (IPAddress a in Addresses) + ret.Add (a.ToString ()); + return "<" + String.Join (", ", ret) + ">"; + } + bool AddressesAreEqual (List one, List two) { if (one == two) @@ -80,12 +100,20 @@ bool HardwareAddressesAreEqual (byte[] one, byte[] two) } } - //[Test] + [Test] public void DotNetInterfacesShouldEqualJavaInterfaces () { List dotnetInterfaces = GetInfos (MNetworkInterface.GetAllNetworkInterfaces ()); List javaInterfaces = GetInfos (JNetworkInterface.NetworkInterfaces); + Console.WriteLine ("Mono interfaces:"); + foreach (InterfaceInfo inf in dotnetInterfaces) + Console.WriteLine (inf); + + Console.WriteLine ("Java interfaces:"); + foreach (InterfaceInfo inf in javaInterfaces) + Console.WriteLine (inf); + Assert.IsNotNull (dotnetInterfaces, "#1.1"); Assert.IsTrue (dotnetInterfaces.Count > 0, "#1.2"); @@ -123,7 +151,11 @@ public void DotNetInterfacesShouldEqualJavaInterfaces () var addr = addresses.NextElement () as InetAddress; if (addr == null) continue; - ret.Add (new IPAddress (addr.GetAddress ())); + var ipv6 = addr as Inet6Address; + if (ipv6 != null && (ipv6.IsLinkLocalAddress || ipv6.IsMCLinkLocal)) + ret.Add (new IPAddress (addr.GetAddress (), ipv6.ScopeId)); + else + ret.Add (new IPAddress (addr.GetAddress ())); } return ret; @@ -146,7 +178,7 @@ byte[] GetHardwareAddress (MNetworkInterface inf) { byte[] bytes = inf.GetPhysicalAddress ().GetAddressBytes (); // Map to android's idea of device address - if (bytes.Length == 0 || inf.NetworkInterfaceType == NetworkInterfaceType.Unknown || inf.NetworkInterfaceType == NetworkInterfaceType.Tunnel) + if (bytes.Length == 0 || inf.NetworkInterfaceType == NetworkInterfaceType.Tunnel) return null; return bytes; } diff --git a/src/monodroid/jni/monodroid-networkinfo.c b/src/monodroid/jni/monodroid-networkinfo.c index 9c56f176d89..37b564c5cd3 100644 --- a/src/monodroid/jni/monodroid-networkinfo.c +++ b/src/monodroid/jni/monodroid-networkinfo.c @@ -46,6 +46,7 @@ java_classes_init (void) { JNIEnv *env = get_jnienv (); NetworkInterface_class = (*env)->FindClass (env, "java/net/NetworkInterface"); + NetworkInterface_class = (*env)->NewGlobalRef (env, NetworkInterface_class); NetworkInterface_getByName = (*env)->GetStaticMethodID (env, NetworkInterface_class, "getByName", "(Ljava/lang/String;)Ljava/net/NetworkInterface;"); NetworkInterface_isUp = (*env)->GetMethodID (env, NetworkInterface_class, "isUp", "()Z"); NetworkInterface_supportsMulticast = (*env)->GetMethodID (env, NetworkInterface_class, "supportsMulticast", "()Z"); diff --git a/src/monodroid/jni/xamarin_getifaddrs.c b/src/monodroid/jni/xamarin_getifaddrs.c index bb3eb59cf5b..a5a5d3a9101 100644 --- a/src/monodroid/jni/xamarin_getifaddrs.c +++ b/src/monodroid/jni/xamarin_getifaddrs.c @@ -25,80 +25,186 @@ #include "logger.h" #include "xamarin_getifaddrs.h" -/* These aren't defined in android's rtnetlink.h (as of ndk 9d). We define fake values for them if - * they aren't found so that the debug code works properly. We could skip them but future versions - * of the NDK might include definitions for them. +/* Some of these aren't defined in android's rtnetlink.h (as of ndk 16). We define values for all of + * them if they aren't found so that the debug code works properly. We could skip them but future + * versions of the NDK might include definitions for them. + * Values are taken from Linux headers shipped with glibc */ +#ifndef IFLA_UNSPEC +#define IFLA_UNSPEC 0 +#endif + +#ifndef IFLA_ADDRESS +#define IFLA_ADDRESS 1 +#endif + +#ifndef IFLA_BROADCAST +#define IFLA_BROADCAST 2 +#endif + +#ifndef IFLA_IFNAME +#define IFLA_IFNAME 3 +#endif + +#ifndef IFLA_MTU +#define IFLA_MTU 4 +#endif + +#ifndef IFLA_LINK +#define IFLA_LINK 5 +#endif + +#ifndef IFLA_QDISC +#define IFLA_QDISC 6 +#endif + +#ifndef IFLA_STATS +#define IFLA_STATS 7 +#endif + +#ifndef IFLA_COST +#define IFLA_COST 8 +#endif + +#ifndef IFLA_PRIORITY +#define IFLA_PRIORITY 9 +#endif + +#ifndef IFLA_MASTER +#define IFLA_MASTER 10 +#endif + +#ifndef IFLA_WIRELESS +#define IFLA_WIRELESS 11 +#endif + +#ifndef IFLA_PROTINFO +#define IFLA_PROTINFO 12 +#endif + +#ifndef IFLA_TXQLEN +#define IFLA_TXQLEN 13 +#endif + +#ifndef IFLA_MAP +#define IFLA_MAP 14 +#endif + +#ifndef IFLA_WEIGHT +#define IFLA_WEIGHT 15 +#endif + +#ifndef IFLA_OPERSTATE +#define IFLA_OPERSTATE 16 +#endif + +#ifndef IFLA_LINKMODE +#define IFLA_LINKMODE 17 +#endif + #ifndef IFLA_LINKINFO -#define IFLA_LINKINFO 1000 +#define IFLA_LINKINFO 18 #endif #ifndef IFLA_NET_NS_PID -#define IFLA_NET_NS_PID 1001 +#define IFLA_NET_NS_PID 19 #endif #ifndef IFLA_IFALIAS -#define IFLA_IFALIAS 1002 +#define IFLA_IFALIAS 20 #endif #ifndef IFLA_NUM_VF -#define IFLA_NUM_VF 1003 +#define IFLA_NUM_VF 21 #endif #ifndef IFLA_VFINFO_LIST -#define IFLA_VFINFO_LIST 1004 +#define IFLA_VFINFO_LIST 22 #endif #ifndef IFLA_STATS64 -#define IFLA_STATS64 1005 +#define IFLA_STATS64 23 #endif #ifndef IFLA_VF_PORTS -#define IFLA_VF_PORTS 1006 +#define IFLA_VF_PORTS 24 #endif #ifndef IFLA_PORT_SELF -#define IFLA_PORT_SELF 1007 +#define IFLA_PORT_SELF 25 #endif #ifndef IFLA_AF_SPEC -#define IFLA_AF_SPEC 1008 +#define IFLA_AF_SPEC 26 #endif #ifndef IFLA_GROUP -#define IFLA_GROUP 1009 +#define IFLA_GROUP 27 #endif #ifndef IFLA_NET_NS_FD -#define IFLA_NET_NS_FD 1010 +#define IFLA_NET_NS_FD 28 #endif #ifndef IFLA_EXT_MASK -#define IFLA_EXT_MASK 1011 +#define IFLA_EXT_MASK 29 #endif #ifndef IFLA_PROMISCUITY -#define IFLA_PROMISCUITY 1012 +#define IFLA_PROMISCUITY 30 #endif #ifndef IFLA_NUM_TX_QUEUES -#define IFLA_NUM_TX_QUEUES 1013 +#define IFLA_NUM_TX_QUEUES 31 #endif #ifndef IFLA_NUM_RX_QUEUES -#define IFLA_NUM_RX_QUEUES 1014 +#define IFLA_NUM_RX_QUEUES 32 #endif #ifndef IFLA_CARRIER -#define IFLA_CARRIER 1015 +#define IFLA_CARRIER 33 #endif #ifndef IFLA_PHYS_PORT_ID -#define IFLA_PHYS_PORT_ID 1016 +#define IFLA_PHYS_PORT_ID 34 +#endif + +#ifndef IFLA_CARRIER_CHANGES +#define IFLA_CARRIER_CHANGES 35 +#endif + +#ifndef IFLA_PHYS_SWITCH_ID +#define IFLA_PHYS_SWITCH_ID 36 #endif -/* The amount of data we read from the kernel in one call */ -#define RESPONSE_BUFFER_SIZE 1024 +#ifndef IFLA_LINK_NETNSID +#define IFLA_LINK_NETNSID 37 +#endif + +#ifndef IFLA_PHYS_PORT_NAME +#define IFLA_PHYS_PORT_NAME 38 +#endif + +#ifndef IFLA_PROTO_DOWN +#define IFLA_PROTO_DOWN 39 +#endif + +#ifndef IFLA_GSO_MAX_SEGS +#define IFLA_GSO_MAX_SEGS 40 +#endif + +#ifndef IFLA_GSO_MAX_SIZE +#define IFLA_GSO_MAX_SIZE 41 +#endif + +#ifndef IFLA_PAD +#define IFLA_PAD 42 +#endif + +#ifndef IFLA_XDP +#define IFLA_XDP 43 +#endif /* Maximum interface address label size, should be more than enough */ #define MAX_IFA_LABEL_SIZE 1024 @@ -390,21 +496,30 @@ append_ifaddr (struct _monodroid_ifaddrs *addr, struct _monodroid_ifaddrs **ifad static int parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifaddrs_head, struct _monodroid_ifaddrs **last_ifaddr) { - ssize_t length; struct msghdr netlink_reply; struct iovec reply_vector; struct nlmsghdr *current_message; struct _monodroid_ifaddrs *addr; - unsigned char response [RESPONSE_BUFFER_SIZE]; + int ret = -1; + unsigned char *response = NULL; assert (session); assert (ifaddrs_head); assert (last_ifaddr); - + + int buf_size = getpagesize (); + log_debug (LOG_NETLINK, "receive buffer size == %d", buf_size); + + response = (unsigned char*)malloc (sizeof (*response) * buf_size); + if (!response) { + goto cleanup; + } + + ssize_t length = 0; while (1) { - memset (response, 0, RESPONSE_BUFFER_SIZE); + memset (response, 0, buf_size); memset (&reply_vector, 0, sizeof (reply_vector)); - reply_vector.iov_len = RESPONSE_BUFFER_SIZE; + reply_vector.iov_len = buf_size; reply_vector.iov_base = response; memset (&netlink_reply, 0, sizeof (netlink_reply)); @@ -413,17 +528,34 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd netlink_reply.msg_iovlen = 1; netlink_reply.msg_iov = &reply_vector; - log_debug (LOG_NETLINK, "receiving message...\n"); length = recvmsg (session->sock_fd, &netlink_reply, 0); log_debug (LOG_NETLINK, " length == %d\n", (int)length); if (length < 0) { log_debug (LOG_NETLINK, "Failed to receive reply from netlink. %s\n", strerror (errno)); - return -1; + goto cleanup; } +#if DEBUG + log_debug (LOG_NETLINK, "response flags:"); + if (netlink_reply.msg_flags == 0) + log_debug (LOG_NETLINK, " [NONE]"); + else { + if (netlink_reply.msg_flags & MSG_EOR) + log_debug (LOG_NETLINK, " MSG_EOR"); + if (netlink_reply.msg_flags & MSG_TRUNC) + log_debug (LOG_NETLINK, " MSG_TRUNC"); + if (netlink_reply.msg_flags & MSG_CTRUNC) + log_debug (LOG_NETLINK, " MSG_CTRUNC"); + if (netlink_reply.msg_flags & MSG_OOB) + log_debug (LOG_NETLINK, " MSG_OOB"); + if (netlink_reply.msg_flags & MSG_ERRQUEUE) + log_debug (LOG_NETLINK, " MSG_ERRQUEUE"); + } +#endif + if (length == 0) - return 0; /* done, apparently */ + break; for (current_message = (struct nlmsghdr*)response; current_message && NLMSG_OK (current_message, length); current_message = NLMSG_NEXT (current_message, length)) { log_debug (LOG_NETLINK, "next message... (type: %u)\n", current_message->nlmsg_type); @@ -432,24 +564,39 @@ parse_netlink_reply (netlink_session *session, struct _monodroid_ifaddrs **ifadd case RTM_NEWLINK: log_debug (LOG_NETLINK, " dumping link...\n"); addr = get_link_info (current_message); - if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) - return -1; + if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) { + ret = -1; + goto cleanup; + } log_debug (LOG_NETLINK, " done\n"); break; case RTM_NEWADDR: log_debug (LOG_NETLINK, " got an address\n"); addr = get_link_address (current_message, ifaddrs_head); - if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) - return -1; + if (!addr || append_ifaddr (addr, ifaddrs_head, last_ifaddr) < 0) { + ret = -1; + goto cleanup; + } break; case NLMSG_DONE: log_debug (LOG_NETLINK, " message done\n"); - return 0; + ret = 0; + goto cleanup; + break; + + default: + log_debug (LOG_NETLINK, " message type: %u", current_message->nlmsg_type); + break; } } - } + } + + cleanup: + if (response) + free (response); + return ret; } static int @@ -636,7 +783,7 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net netmask_data [prefix_bytes + 1] = 0xff << (8 - (prefix_length % 8)); log_debug (LOG_NETLINK, " netmask is: "); for (i = 0; i < data_length; i++) { - log_debug (LOG_NETLINK, "%s%u", i == 0 ? "" : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]); + log_debug (LOG_NETLINK, "%s%u", i == 0 ? " " : ".", (unsigned char)ifa->ifa_netmask->sa_data [i]); } log_debug (LOG_NETLINK, "\n"); } @@ -645,10 +792,11 @@ calculate_address_netmask (struct _monodroid_ifaddrs *ifa, struct ifaddrmsg *net return 0; } + static struct _monodroid_ifaddrs * get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **ifaddrs_head) { - size_t length; + size_t length = 0; struct rtattr *attribute; struct ifaddrmsg *net_address; struct _monodroid_ifaddrs *ifa = NULL; @@ -658,6 +806,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if assert (message); net_address = NLMSG_DATA (message); length = IFA_PAYLOAD (message); + log_debug (LOG_NETLINK, " address data length: %u", length); if (length <= 0) { goto error; } @@ -670,14 +819,17 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if ifa->ifa_flags = get_interface_flags_by_index (net_address->ifa_index, ifaddrs_head); attribute = IFA_RTA (net_address); + log_debug (LOG_NETLINK, " reading attributes"); while (RTA_OK (attribute, length)) { payload_size = RTA_PAYLOAD (attribute); + log_debug (LOG_NETLINK, " attribute payload_size == %u\n", payload_size); sa = NULL; switch (attribute->rta_type) { case IFA_LABEL: { int room_for_trailing_null = 0; + log_debug (LOG_NETLINK, " attribute type: LABEL"); if (payload_size > MAX_IFA_LABEL_SIZE) { payload_size = MAX_IFA_LABEL_SIZE; room_for_trailing_null = 1; @@ -697,9 +849,10 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if } case IFA_LOCAL: + log_debug (LOG_NETLINK, " attribute type: LOCAL"); if (ifa->ifa_addr) { /* P2P protocol, set the dst/broadcast address union from the original address. - * Since ifa_addr is set it means IFA_ADDRESST occured earlier and that address + * Since ifa_addr is set it means IFA_ADDRESS occured earlier and that address * is indeed the P2P destination one. */ ifa->_monodroid_ifa_dstaddr = ifa->ifa_addr; @@ -709,6 +862,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; case IFA_BROADCAST: + log_debug (LOG_NETLINK, " attribute type: BROADCAST"); if (ifa->_monodroid_ifa_dstaddr) { /* IFA_LOCAL happened earlier, undo its effect here */ free (ifa->_monodroid_ifa_dstaddr); @@ -718,6 +872,7 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if break; case IFA_ADDRESS: + log_debug (LOG_NETLINK, " attribute type: ADDRESS"); if (ifa->ifa_addr) { /* Apparently IFA_LOCAL occured earlier and we have a P2P connection * here. IFA_LOCAL carries the destination address, move it there @@ -727,6 +882,26 @@ get_link_address (const struct nlmsghdr *message, struct _monodroid_ifaddrs **if } sa = &ifa->ifa_addr; break; + + case IFA_UNSPEC: + log_debug (LOG_NETLINK, " attribute type: UNSPEC"); + break; + + case IFA_ANYCAST: + log_debug (LOG_NETLINK, " attribute type: ANYCAST"); + break; + + case IFA_CACHEINFO: + log_debug (LOG_NETLINK, " attribute type: CACHEINFO"); + break; + + case IFA_MULTICAST: + log_debug (LOG_NETLINK, " attribute type: MULTICAST"); + break; + + default: + log_debug (LOG_NETLINK, " attribute type: %u", attribute->rta_type); + break; } if (sa) { @@ -899,6 +1074,15 @@ struct enumvalue iflas[] = { ENUM_VALUE_ENTRY (IFLA_NUM_RX_QUEUES), ENUM_VALUE_ENTRY (IFLA_CARRIER), ENUM_VALUE_ENTRY (IFLA_PHYS_PORT_ID), + ENUM_VALUE_ENTRY (IFLA_CARRIER_CHANGES), + ENUM_VALUE_ENTRY (IFLA_PHYS_SWITCH_ID), + ENUM_VALUE_ENTRY (IFLA_LINK_NETNSID), + ENUM_VALUE_ENTRY (IFLA_PHYS_PORT_NAME), + ENUM_VALUE_ENTRY (IFLA_PROTO_DOWN), + ENUM_VALUE_ENTRY (IFLA_GSO_MAX_SEGS), + ENUM_VALUE_ENTRY (IFLA_GSO_MAX_SIZE), + ENUM_VALUE_ENTRY (IFLA_PAD), + ENUM_VALUE_ENTRY (IFLA_XDP), { -1, 0 } }; From 1cbca7eb713e0a39978356413b962961f2579a37 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 6 Sep 2017 14:46:30 +0200 Subject: [PATCH 27/29] [tests] process the logcat only when definitions are set (#822) - this makes the timing processing optional and also makes it easier to use the XA's tests infrastructure outside of XA --- build-tools/scripts/UnitTestApks.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/build-tools/scripts/UnitTestApks.targets b/build-tools/scripts/UnitTestApks.targets index b66fcc08552..0bc00ec9c33 100644 --- a/build-tools/scripts/UnitTestApks.targets +++ b/build-tools/scripts/UnitTestApks.targets @@ -150,6 +150,7 @@ Date: Wed, 6 Sep 2017 11:12:18 -0500 Subject: [PATCH 28/29] Bump to Java.Interop/master/7d9d72a --- external/Java.Interop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/Java.Interop b/external/Java.Interop index 16be390ab82..7d9d72a538c 160000 --- a/external/Java.Interop +++ b/external/Java.Interop @@ -1 +1 @@ -Subproject commit 16be390ab82a5b1dda34aa2cb3237c9634a37266 +Subproject commit 7d9d72a538c4d7b9058e8e002c7c7138c16f425b From 10bd198a1b322009d36fb5a89819f319d0d3f7fc Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 6 Sep 2017 11:35:27 -0500 Subject: [PATCH 29/29] [jdk] Don't require `javac`/`jar` in $PATH Windows machines do not include Java in their path by default, so it is a better experience to not require it for the build. Changes to make this happen: - `JavaCPath` and `JarPath` are configured in `Configuration.OperatingSystem.props` - Usage of `javac` and `jar` across the repo use appropriate variables now - A couple places, Windows needs `JAVA_HOME` to be set, so we are making use of a new `SetEnvironmentVar` MSBuild task - The `JdkInfo` MSBuild task used in `PrepareWindows.targets` configures `Configuration.OperatingSystem.props` for Java, and also configures `Java.Interop` --- .../android-toolchain.targets | 2 +- .../dependencies/dependencies.projitems | 4 +-- .../scripts/JavaCallableWrappers.targets | 6 ++--- build-tools/scripts/PrepareWindows.targets | 3 ++- ...indows-Configuration.OperatingSystem.props | 3 +++ build-tools/scripts/generate-os-info | 2 ++ .../AcceptAndroidSdkLicenses.cs | 10 +++++++ .../JdkInfo.cs | 22 +++++++++++++--- .../SetEnvironmentVar.cs | 26 +++++++++++++++++++ .../xa-prep-tasks/xa-prep-tasks.csproj | 1 + src/proguard/proguard.targets | 11 ++++++++ ...FixJavaAbstractMethod-APIv1Binding.targets | 4 +-- ...FixJavaAbstractMethod-APIv2Binding.targets | 4 +-- .../Xamarin.Android.McwGen-Tests.targets | 8 +++--- ...in.Android.BindingResolveImportLib1.csproj | 2 +- ...in.Android.BindingResolveImportLib2.csproj | 2 +- ...in.Android.BindingResolveImportLib3.csproj | 2 +- ...in.Android.BindingResolveImportLib4.csproj | 2 +- 18 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/SetEnvironmentVar.cs diff --git a/build-tools/android-toolchain/android-toolchain.targets b/build-tools/android-toolchain/android-toolchain.targets index 71940cbfcab..66d376dfa2c 100644 --- a/build-tools/android-toolchain/android-toolchain.targets +++ b/build-tools/android-toolchain/android-toolchain.targets @@ -128,7 +128,7 @@ <_AndroidMxeOutput Include="@(_AndroidMxeToolchain->'$(AndroidMxeFullPath)\%(Identity)\lib\libz.a')" /> - + intltool - + 1.8 $(MSBuildThisFileDirectory)..\scripts\javac-version - javac -version 2>&1 + "$(JavaCPath)" -version 2>&1 $(_AptGetInstall) openjdk-8-jdk diff --git a/build-tools/scripts/JavaCallableWrappers.targets b/build-tools/scripts/JavaCallableWrappers.targets index d2159085488..497b8957118 100644 --- a/build-tools/scripts/JavaCallableWrappers.targets +++ b/build-tools/scripts/JavaCallableWrappers.targets @@ -30,15 +30,15 @@ <_MonoAndroidJar>$(OutputPath)mono.android.jar diff --git a/build-tools/scripts/Windows-Configuration.OperatingSystem.props b/build-tools/scripts/Windows-Configuration.OperatingSystem.props index c71e8887009..ec8104a1cfb 100644 --- a/build-tools/scripts/Windows-Configuration.OperatingSystem.props +++ b/build-tools/scripts/Windows-Configuration.OperatingSystem.props @@ -9,5 +9,8 @@ x86_64-win32 $([System.Environment]::ProcessorCount) 64 + @JAVA_HOME@ + $(JavaSdkDirectory)\bin\javac.exe + $(JavaSdkDirectory)\bin\jar.exe \ No newline at end of file diff --git a/build-tools/scripts/generate-os-info b/build-tools/scripts/generate-os-info index e5a4b24490e..c471a67ab34 100755 --- a/build-tools/scripts/generate-os-info +++ b/build-tools/scripts/generate-os-info @@ -120,6 +120,8 @@ cat < "$1" $HOST_CC64 $HOST_CXX32 $HOST_CXX64 + javac + jar EOF diff --git a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs index a07923579e1..467fe24310e 100644 --- a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs +++ b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/AcceptAndroidSdkLicenses.cs @@ -11,11 +11,21 @@ public class AcceptAndroidSdkLicenses : Task [Required] public string AndroidSdkDirectory { get; set; } + public string JavaSdkDirectory { get; set; } + public override bool Execute () { + Log.LogMessage (MessageImportance.Low, $"Task {nameof (AcceptAndroidSdkLicenses)}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidSdkDirectory)}: {AndroidSdkDirectory}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (JavaSdkDirectory)}: {JavaSdkDirectory}"); + var licdir = Path.Combine (Path.Combine (AndroidSdkDirectory, "licenses")); Directory.CreateDirectory (licdir); + if (!string.IsNullOrEmpty (JavaSdkDirectory)) { + Environment.SetEnvironmentVariable ("JAVA_HOME", JavaSdkDirectory); + } + string _; var path = Which.GetProgramLocation ("sdkmanager", out _, new [] { Path.Combine (AndroidSdkDirectory, "tools", "bin") }); var psi = new ProcessStartInfo (path, "--licenses") { UseShellExecute = false, RedirectStandardInput = true }; diff --git a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/JdkInfo.cs b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/JdkInfo.cs index 2d8d23389ba..5bf75f31c9a 100644 --- a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/JdkInfo.cs +++ b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/JdkInfo.cs @@ -10,7 +10,10 @@ namespace Xamarin.Android.BuildTools.PrepTasks public class JdkInfo : Task { [Required] - public ITaskItem Output { get; set; } + public ITaskItem ConfigurationOperatingSystemProps { get; set; } + + [Required] + public ITaskItem JdkInfoProps { get; set; } public string AndroidNdkPath { get; set; } @@ -21,7 +24,8 @@ public class JdkInfo : Task public override bool Execute () { Log.LogMessage (MessageImportance.Low, $"Task {nameof (JdkInfo)}"); - Log.LogMessage (MessageImportance.Low, $" {nameof (Output)}: {Output}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (ConfigurationOperatingSystemProps)}: {ConfigurationOperatingSystemProps}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (JdkInfoProps)}: {JdkInfoProps}"); Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidNdkPath)}: {AndroidNdkPath}"); Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidSdkPath)}: {AndroidSdkPath}"); Log.LogMessage (MessageImportance.Low, $" {nameof (JavaSdkPath)}: {JavaSdkPath}"); @@ -40,6 +44,12 @@ public override bool Execute () Log.LogMessage (MessageImportance.Low, $" {nameof (AndroidSdk.JavaSdkPath)}: {javaSdkPath}"); + if (File.Exists (ConfigurationOperatingSystemProps.ItemSpec)) { + var xml = File.ReadAllText (ConfigurationOperatingSystemProps.ItemSpec); + if (xml.Contains("@JAVA_HOME@")) + File.WriteAllText (ConfigurationOperatingSystemProps.ItemSpec, xml.Replace ("@JAVA_HOME@", javaSdkPath)); + } + var jvmPath = Path.Combine (javaSdkPath, "jre", "bin", "server", "jvm.dll"); if (!File.Exists (jvmPath)) { Log.LogError ($"JdkJvmPath not found at {jvmPath}"); @@ -55,8 +65,8 @@ public override bool Execute () includeXmlTags.AppendLine ($""); } - Directory.CreateDirectory (Path.GetDirectoryName (Output.ItemSpec)); - File.WriteAllText (Output.ItemSpec, $@" + Directory.CreateDirectory (Path.GetDirectoryName (JdkInfoProps.ItemSpec)); + File.WriteAllText (JdkInfoProps.ItemSpec, $@" @@ -67,6 +77,10 @@ public override bool Execute () + + {Path.Combine (javaSdkPath, "bin", "javac.exe")} + {Path.Combine (javaSdkPath, "bin", "jar.exe")} + "); return !Log.HasLoggedErrors; diff --git a/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/SetEnvironmentVar.cs b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/SetEnvironmentVar.cs new file mode 100644 index 00000000000..07b26281134 --- /dev/null +++ b/build-tools/xa-prep-tasks/Xamarin.Android.BuildTools.PrepTasks/SetEnvironmentVar.cs @@ -0,0 +1,26 @@ +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System; + +namespace Xamarin.Android.BuildTools.PrepTasks +{ + public class SetEnvironmentVar : Task + { + [Required] + public string Name { get; set; } + + [Required] + public string Value { get; set; } + + public override bool Execute () + { + Log.LogMessage (MessageImportance.Low, $"Task {nameof (SetEnvironmentVar)}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (Name)}: {Name}"); + Log.LogMessage (MessageImportance.Low, $" {nameof (Value)}: {Value}"); + + Environment.SetEnvironmentVariable (Name, Value); + + return !Log.HasLoggedErrors; + } + } +} diff --git a/build-tools/xa-prep-tasks/xa-prep-tasks.csproj b/build-tools/xa-prep-tasks/xa-prep-tasks.csproj index 4b65e7064ea..f6408518627 100644 --- a/build-tools/xa-prep-tasks/xa-prep-tasks.csproj +++ b/build-tools/xa-prep-tasks/xa-prep-tasks.csproj @@ -45,6 +45,7 @@ + diff --git a/src/proguard/proguard.targets b/src/proguard/proguard.targets index a4596b74ab1..1af3dfe9ce7 100644 --- a/src/proguard/proguard.targets +++ b/src/proguard/proguard.targets @@ -1,5 +1,11 @@ + + + diff --git a/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding.targets b/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding.targets index d53c4db09c7..29b53d34c3e 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding.targets +++ b/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding/Xamarin.Android.FixJavaAbstractMethod-APIv1Binding.targets @@ -5,8 +5,8 @@ Inputs="@(InputJarSource)" Outputs="@(InputJar)"> - - + + diff --git a/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding.targets b/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding.targets index d53c4db09c7..29b53d34c3e 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding.targets +++ b/tests/CodeGen-Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding/Xamarin.Android.FixJavaAbstractMethod-APIv2Binding.targets @@ -5,8 +5,8 @@ Inputs="@(InputJarSource)" Outputs="@(InputJar)"> - - + + diff --git a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets index 631f0d26354..c48e56feeec 100644 --- a/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets +++ b/tests/CodeGen-Binding/Xamarin.Android.McwGen-Tests/Xamarin.Android.McwGen-Tests.targets @@ -5,11 +5,11 @@ Inputs="@(XamarinTestJar);%(IgnoreJar.Source)" Outputs="@(EmbeddedJar);@(IgnoreJar)"> - - + + - - + + diff --git a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib1/Xamarin.Android.BindingResolveImportLib1.csproj b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib1/Xamarin.Android.BindingResolveImportLib1.csproj index acc38c9412a..3c74944ee39 100644 --- a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib1/Xamarin.Android.BindingResolveImportLib1.csproj +++ b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib1/Xamarin.Android.BindingResolveImportLib1.csproj @@ -59,7 +59,7 @@ - + diff --git a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib2/Xamarin.Android.BindingResolveImportLib2.csproj b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib2/Xamarin.Android.BindingResolveImportLib2.csproj index 32ad6d21993..d2a2d26f695 100644 --- a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib2/Xamarin.Android.BindingResolveImportLib2.csproj +++ b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib2/Xamarin.Android.BindingResolveImportLib2.csproj @@ -77,7 +77,7 @@ - + diff --git a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib3/Xamarin.Android.BindingResolveImportLib3.csproj b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib3/Xamarin.Android.BindingResolveImportLib3.csproj index 14ccea9e76c..cdeb5820481 100644 --- a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib3/Xamarin.Android.BindingResolveImportLib3.csproj +++ b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib3/Xamarin.Android.BindingResolveImportLib3.csproj @@ -77,7 +77,7 @@ - + diff --git a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib4/Xamarin.Android.BindingResolveImportLib4.csproj b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib4/Xamarin.Android.BindingResolveImportLib4.csproj index 5f340f95022..70f4fd595bc 100644 --- a/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib4/Xamarin.Android.BindingResolveImportLib4.csproj +++ b/tests/ResolveImports/Xamarin.Android.BindingResolveImportLib4/Xamarin.Android.BindingResolveImportLib4.csproj @@ -75,7 +75,7 @@ - +