public void CheckMonoDebugIsAddedToEnvironment([Values("", "Normal", "Offline")] string sequencePointsMode)
        {
            const string supportedAbis = "armeabi-v7a;x86";

            var proj = new XamarinAndroidApplicationProject()
            {
                IsRelease = true,
            };

            proj.SetProperty("_AndroidSequencePointsMode", sequencePointsMode);
            proj.SetAndroidSupportedAbis(supportedAbis);
            using (var b = CreateApkBuilder()) {
                Assert.IsTrue(b.Build(proj), "Build should have succeeded.");

                string        intermediateOutputDir = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath);
                List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.Count > 0, $"No environment variables defined");

                string monoDebugVar;
                bool   monoDebugVarFound = envvars.TryGetValue("MONO_DEBUG", out monoDebugVar);
                if (String.IsNullOrEmpty(sequencePointsMode))
                {
                    Assert.IsFalse(monoDebugVarFound, $"environment should not contain MONO_DEBUG={monoDebugVar}");
                }
                else
                {
                    Assert.IsTrue(monoDebugVarFound, "environment should contain MONO_DEBUG");
                    Assert.AreEqual("gen-compact-seq-points", monoDebugVar, "environment should contain MONO_DEBUG=gen-compact-seq-points");
                }

                EnvironmentHelper.AssertValidEnvironmentSharedLibrary(intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis);
            }
        }
        public void CheckHttpClientHandlerType()
        {
            var proj = new XamarinAndroidApplicationProject()
            {
                IsRelease = true,
            };
            var httpClientHandlerVarName = "XA_HTTP_CLIENT_HANDLER_TYPE";
            var expectedDefaultValue     = "System.Net.Http.HttpClientHandler, System.Net.Http";
            var expectedUpdatedValue     = "Xamarin.Android.Net.AndroidClientHandler";
            var supportedAbis            = "armeabi-v7a;arm64-v8a";

            proj.SetAndroidSupportedAbis(supportedAbis);

            using (var b = CreateApkBuilder()) {
                proj.SetProperty("AndroidHttpClientHandlerType", expectedDefaultValue);
                Assert.IsTrue(b.Build(proj), "Build should have succeeded.");
                var           intermediateOutputDir = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath);
                List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.ContainsKey(httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'.");
                Assert.AreEqual(expectedDefaultValue, envvars[httpClientHandlerVarName]);

                proj.SetProperty("AndroidHttpClientHandlerType", expectedUpdatedValue);
                Assert.IsTrue(b.Build(proj), "Second build should have succeeded.");
                envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                envvars  = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.ContainsKey(httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'.");
                Assert.AreEqual(expectedUpdatedValue, envvars[httpClientHandlerVarName]);
            }
        }
        public void CheckConcurrentGC()
        {
            var proj = new XamarinAndroidApplicationProject()
            {
                IsRelease = true,
            };
            var gcVarName            = "MONO_GC_PARAMS";
            var expectedDefaultValue = "major=marksweep";
            var expectedUpdatedValue = "major=marksweep-conc";
            var supportedAbis        = "armeabi-v7a;arm64-v8a";

            proj.SetAndroidSupportedAbis(supportedAbis);

            using (var b = CreateApkBuilder()) {
                proj.SetProperty("AndroidEnableSGenConcurrent", "False");
                Assert.IsTrue(b.Build(proj), "Build should have succeeded.");
                var intermediateOutputDir = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath);
                // AndroidEnableSGenConcurrent=False by default
                List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.ContainsKey(gcVarName), $"Environment should contain '{gcVarName}'.");
                Assert.AreEqual(expectedDefaultValue, envvars[gcVarName], $"'{gcVarName}' should have been '{expectedDefaultValue}' when concurrent GC is disabled.");

                proj.SetProperty("AndroidEnableSGenConcurrent", "True");
                Assert.IsTrue(b.Build(proj), "Second build should have succeeded.");
                envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                envvars  = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.ContainsKey(gcVarName), $"Environment should contain '{gcVarName}'.");
                Assert.AreEqual(expectedUpdatedValue, envvars[gcVarName], $"'{gcVarName}' should have been '{expectedUpdatedValue}' when concurrent GC is enabled.");
            }
        }
        public void CheckBuildIdIsUnique([Values("apk", "aab")] string packageFormat)
        {
            const string supportedAbis = "armeabi-v7a;x86";

            Dictionary <string, string> buildIds = new Dictionary <string, string> ();
            var proj = new XamarinAndroidApplicationProject()
            {
                IsRelease = true,
            };

            proj.SetProperty(proj.ReleaseProperties, "MonoSymbolArchive", "True");
            proj.SetProperty(proj.ReleaseProperties, "DebugSymbols", "true");
            proj.SetProperty(proj.ReleaseProperties, "DebugType", "PdbOnly");
            proj.SetProperty(proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, "true");
            proj.SetProperty(proj.ReleaseProperties, "AndroidPackageFormat", packageFormat);
            proj.SetAndroidSupportedAbis(supportedAbis);
            using (var b = CreateApkBuilder()) {
                b.Verbosity           = Microsoft.Build.Framework.LoggerVerbosity.Diagnostic;
                b.ThrowOnBuildFailure = false;
                Assert.IsTrue(b.Build(proj), "first build failed");
                var    outputPath        = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath);
                var    archivePath       = Path.Combine(outputPath, $"{proj.PackageName}.{packageFormat}.mSYM");
                var    allFilesInArchive = Directory.GetFiles(archivePath, "*", SearchOption.AllDirectories);
                string extension         = "dll";
                Assert.IsTrue(allFilesInArchive.Any(x => Path.GetFileName(x) == $"{proj.ProjectName}.{extension}"), $"{proj.ProjectName}.{extension} should exist in {archivePath}");
                extension = "pdb";
                Assert.IsTrue(allFilesInArchive.Any(x => Path.GetFileName(x) == $"{proj.ProjectName}.{extension}"), $"{proj.ProjectName}.{extension} should exist in {archivePath}");

                string        intermediateOutputDir = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath);
                List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.Count > 0, $"No environment variables defined");

                string buildID;
                Assert.IsTrue(envvars.TryGetValue("XAMARIN_BUILD_ID", out buildID), "The environment should contain a XAMARIN_BUILD_ID");
                buildIds.Add("all", buildID);

                var msymDirectory = Path.Combine(Root, b.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}.{packageFormat}.mSYM");
                Assert.IsTrue(File.Exists(Path.Combine(msymDirectory, "manifest.xml")), "manifest.xml should exist in", msymDirectory);
                var doc = XDocument.Load(Path.Combine(msymDirectory, "manifest.xml"));

                Assert.IsTrue(doc.Element("mono-debug")
                              .Elements()
                              .Any(x => x.Name == "app-id" && x.Value == proj.PackageName), "app-id is has an incorrect value.");
                var buildId = buildIds.First().Value;
                Assert.IsTrue(doc.Element("mono-debug")
                              .Elements()
                              .Any(x => x.Name == "build-id" && x.Value == buildId), "build-id is has an incorrect value.");

                EnvironmentHelper.AssertValidEnvironmentSharedLibrary(intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis);
            }
        }
        public void BuildWithTlsProvider(string androidTlsProvider, bool isRelease, bool expected)
        {
            var proj = new XamarinAndroidApplicationProject()
            {
                IsRelease = isRelease,
            };
            var supportedAbis = new string [] { "armeabi-v7a", "arm64-v8a" };

            proj.SetAndroidSupportedAbis(supportedAbis);

            using (var b = CreateApkBuilder(Path.Combine("temp", $"BuildWithTlsProvider_{androidTlsProvider}_{isRelease}_{expected}"))) {
                proj.SetProperty("AndroidTlsProvider", androidTlsProvider);
                Assert.IsTrue(b.Build(proj), "Build should have succeeded.");
                var intermediateOutputDir = Path.Combine(Root, b.ProjectDirectory, proj.IntermediateOutputPath);
                var apk = Path.Combine(intermediateOutputDir, "android", "bin", "UnnamedProject.UnnamedProject.apk");
                using (var zipFile = ZipHelper.OpenZip(apk)) {
                    foreach (var abi in supportedAbis)
                    {
                        if (expected)
                        {
                            Assert.IsNotNull(ZipHelper.ReadFileFromZip(zipFile,
                                                                       $"lib/{abi}/libmono-btls-shared.so"),
                                             $"lib/{abi}/libmono-btls-shared.so should exist in the apk.");
                        }
                        else
                        {
                            Assert.IsNull(ZipHelper.ReadFileFromZip(zipFile,
                                                                    $"lib/{abi}/libmono-btls-shared.so"),
                                          $"lib/{abi}/libmono-btls-shared.so should not exist in the apk.");
                        }
                    }
                }
                List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, string.Join(";", supportedAbis), true);
                Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                Assert.IsTrue(envvars.ContainsKey("XA_TLS_PROVIDER"), "Environment should contain XA_TLS_PROVIDER.");
                if (androidTlsProvider == string.Empty)
                {
                    Assert.AreEqual("btls", envvars["XA_TLS_PROVIDER"], "'XA_TLS_PROVIDER' should have been 'btls' when provider is not set.");
                }
                else
                {
                    Assert.AreEqual(androidTlsProvider, envvars["XA_TLS_PROVIDER"], $"'XA_TLS_PROVIDER' should have been '{androidTlsProvider}'.");
                }
            }
        }
Ejemplo n.º 6
0
        public void DotNetBuildLibrary(bool isRelease, bool duplicateAar)
        {
            var path    = Path.Combine("temp", TestName);
            var env_var = "MY_ENVIRONMENT_VAR";
            var env_val = "MY_VALUE";

            // Setup dependencies App A -> Lib B -> Lib C

            var libC = new XASdkProject(outputType: "Library")
            {
                ProjectName = "LibraryC",
                IsRelease   = isRelease,
                Sources     =
                {
                    new BuildItem.Source("Bar.cs")
                    {
                        TextContent = () => "public class Bar { }",
                    }
                }
            };

            libC.OtherBuildItems.Add(new AndroidItem.AndroidAsset("Assets\\bar\\bar.txt")
            {
                BinaryContent = () => Array.Empty <byte> (),
            });
            var activity = libC.Sources.FirstOrDefault(s => s.Include() == "MainActivity.cs");

            if (activity != null)
            {
                libC.Sources.Remove(activity);
            }
            var libCBuilder = CreateDotNetBuilder(libC, Path.Combine(path, libC.ProjectName));

            Assert.IsTrue(libCBuilder.Build(), $"{libC.ProjectName} should succeed");

            var libB = new XASdkProject(outputType: "Library")
            {
                ProjectName = "LibraryB",
                IsRelease   = isRelease,
                Sources     =
                {
                    new BuildItem.Source("Foo.cs")
                    {
                        TextContent = () => "public class Foo : Bar { }",
                    }
                }
            };

            libB.OtherBuildItems.Add(new AndroidItem.AndroidAsset("Assets\\foo\\foo.txt")
            {
                BinaryContent = () => Array.Empty <byte> (),
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidResource("Resources\\layout\\MyLayout.axml")
            {
                TextContent = () => "<?xml version=\"1.0\" encoding=\"utf-8\" ?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" />"
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidResource("Resources\\raw\\bar.txt")
            {
                BinaryContent = () => Array.Empty <byte> (),
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidEnvironment("env.txt")
            {
                TextContent = () => $"{env_var}={env_val}",
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidEnvironment("sub\\directory\\env.txt")
            {
                TextContent = () => $"{env_var}={env_val}",
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidLibrary("sub\\directory\\foo.jar")
            {
                BinaryContent = () => Convert.FromBase64String(InlineData.JavaClassesJarBase64),
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidLibrary("sub\\directory\\arm64-v8a\\libfoo.so")
            {
                BinaryContent = () => Array.Empty <byte> (),
            });
            libB.OtherBuildItems.Add(new AndroidItem.AndroidLibrary("libfoo.so")
            {
                MetadataValues = "Link=x86\\libfoo.so",
                BinaryContent  = () => Array.Empty <byte> (),
            });
            libB.AddReference(libC);

            activity = libB.Sources.FirstOrDefault(s => s.Include() == "MainActivity.cs");
            if (activity != null)
            {
                libB.Sources.Remove(activity);
            }
            var libBBuilder = CreateDotNetBuilder(libB, Path.Combine(path, libB.ProjectName));

            Assert.IsTrue(libBBuilder.Build(), $"{libB.ProjectName} should succeed");

            // Check .aar file for class library
            var aarPath = Path.Combine(FullProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.aar");

            FileAssert.Exists(aarPath);
            using (var aar = ZipHelper.OpenZip(aarPath)) {
                aar.AssertContainsEntry(aarPath, "assets/foo/foo.txt");
                aar.AssertContainsEntry(aarPath, "res/layout/mylayout.xml");
                aar.AssertContainsEntry(aarPath, "res/raw/bar.txt");
                aar.AssertContainsEntry(aarPath, ".net/__res_name_case_map.txt");
                aar.AssertContainsEntry(aarPath, ".net/env/190E30B3D205731E.env");
                aar.AssertContainsEntry(aarPath, ".net/env/2CBDAB7FEEA94B19.env");
                aar.AssertContainsEntry(aarPath, "libs/A1AFA985571E728E.jar");
                aar.AssertContainsEntry(aarPath, "jni/arm64-v8a/libfoo.so");
                aar.AssertContainsEntry(aarPath, "jni/x86/libfoo.so");
            }

            // Check EmbeddedResource files do not exist
            var assemblyPath = Path.Combine(FullProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.dll");

            FileAssert.Exists(assemblyPath);
            using (var assembly = AssemblyDefinition.ReadAssembly(assemblyPath)) {
                Assert.AreEqual(0, assembly.MainModule.Resources.Count);
            }

            var appA = new XASdkProject {
                ProjectName = "AppA",
                IsRelease   = isRelease,
                Sources     =
                {
                    new BuildItem.Source("Bar.cs")
                    {
                        TextContent = () => "public class Bar : Foo { }",
                    }
                }
            };

            appA.AddReference(libB);
            if (duplicateAar)
            {
                // Test a duplicate @(AndroidLibrary) item with the same path of LibraryB.aar
                appA.OtherBuildItems.Add(new AndroidItem.AndroidLibrary(aarPath));
            }
            var appBuilder = CreateDotNetBuilder(appA, Path.Combine(path, appA.ProjectName));

            Assert.IsTrue(appBuilder.Build(), $"{appA.ProjectName} should succeed");

            // Check .apk for assets, res, and native libraries
            var apkPath = Path.Combine(FullProjectDirectory, appA.OutputPath, $"{appA.PackageName}.apk");

            FileAssert.Exists(apkPath);
            using (var apk = ZipHelper.OpenZip(apkPath)) {
                apk.AssertContainsEntry(apkPath, "assets/foo/foo.txt");
                apk.AssertContainsEntry(apkPath, "assets/bar/bar.txt");
                apk.AssertContainsEntry(aarPath, "res/layout/mylayout.xml");
                apk.AssertContainsEntry(apkPath, "res/raw/bar.txt");
                apk.AssertContainsEntry(apkPath, "lib/arm64-v8a/libfoo.so");
                apk.AssertContainsEntry(apkPath, "lib/x86/libfoo.so");
            }

            // Check classes.dex contains foo.jar
            var intermediate = Path.Combine(FullProjectDirectory, appA.IntermediateOutputPath);
            var dexFile      = Path.Combine(intermediate, "android", "bin", "classes.dex");

            FileAssert.Exists(dexFile);
            string className = "Lcom/xamarin/android/test/msbuildtest/JavaSourceJarTest;";

            Assert.IsTrue(DexUtils.ContainsClass(className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!");

            // Check environment variable
            var environmentFiles     = EnvironmentHelper.GatherEnvironmentFiles(intermediate, "x86", required: true);
            var environmentVariables = EnvironmentHelper.ReadEnvironmentVariables(environmentFiles);

            Assert.IsTrue(environmentVariables.TryGetValue(env_var, out string actual), $"Environment should contain {env_var}");
            Assert.AreEqual(env_val, actual, $"{env_var} should be {env_val}");

            // Check Resource.designer.cs
            var resource_designer_cs = Path.Combine(intermediate, "Resource.designer.cs");

            FileAssert.Exists(resource_designer_cs);
            var resource_designer_text = File.ReadAllText(resource_designer_cs);

            StringAssert.Contains("public const int MyLayout", resource_designer_text);
        }
        public void BuildApplicationWithMonoEnvironment([Values("", "Normal", "Offline")] string sequencePointsMode)
        {
            const string supportedAbis = "armeabi-v7a;x86";

            var lib = new XamarinAndroidLibraryProject {
                ProjectName     = "Library1",
                IsRelease       = true,
                OtherBuildItems = { new AndroidItem.AndroidEnvironment("Mono.env")
                                    {
                                        TextContent = () => "MONO_DEBUG=soft-breakpoints"
                                    }, },
            };
            var app = new XamarinFormsAndroidApplicationProject()
            {
                IsRelease = true,
                AndroidLinkModeRelease = AndroidLinkMode.Full,
                References             =
                {
                    new BuildItem("ProjectReference", "..\\Library1\\Library1.csproj"),
                },
            };
            //LinkSkip one assembly that contains __AndroidLibraryProjects__.zip
            string linkSkip = "FormsViewGroup";

            app.SetProperty("AndroidLinkSkip", linkSkip);
            app.SetProperty("_AndroidSequencePointsMode", sequencePointsMode);
            app.SetAndroidSupportedAbis(supportedAbis);
            using (var libb = CreateDllBuilder(Path.Combine("temp", TestName, lib.ProjectName)))
                using (var appb = CreateApkBuilder(Path.Combine("temp", TestName, app.ProjectName))) {
                    Assert.IsTrue(libb.Build(lib), "Library build should have succeeded.");
                    Assert.IsTrue(appb.Build(app), "App should have succeeded.");
                    Assert.IsTrue(StringAssertEx.ContainsText(appb.LastBuildOutput, $"Save assembly: {linkSkip}"), $"{linkSkip} should be saved, and not linked!");

                    string        intermediateOutputDir = Path.Combine(Root, appb.ProjectDirectory, app.IntermediateOutputPath);
                    List <string> envFiles = EnvironmentHelper.GatherEnvironmentFiles(intermediateOutputDir, supportedAbis, true);
                    Dictionary <string, string> envvars = EnvironmentHelper.ReadEnvironmentVariables(envFiles);
                    Assert.IsTrue(envvars.Count > 0, $"No environment variables defined");

                    string monoDebugVar;
                    Assert.IsTrue(envvars.TryGetValue("MONO_DEBUG", out monoDebugVar), "Environment should contain MONO_DEBUG");
                    Assert.IsFalse(String.IsNullOrEmpty(monoDebugVar), "Environment must contain MONO_DEBUG with a value");
                    Assert.IsTrue(monoDebugVar.IndexOf("soft-breakpoints") >= 0, "Environment must contain MONO_DEBUG with 'soft-breakpoints' in its value");

                    if (!String.IsNullOrEmpty(sequencePointsMode))
                    {
                        Assert.IsTrue(monoDebugVar.IndexOf("gen-compact-seq-points") >= 0, "The values from Mono.env should have been merged into environment");
                    }

                    EnvironmentHelper.AssertValidEnvironmentSharedLibrary(intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis);

                    var assemblyDir = Path.Combine(Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "assets");
                    var rp          = new ReaderParameters {
                        ReadSymbols = false
                    };
                    foreach (var assemblyFile in Directory.EnumerateFiles(assemblyDir, "*.dll"))
                    {
                        using (var assembly = AssemblyDefinition.ReadAssembly(assemblyFile)) {
                            foreach (var module in assembly.Modules)
                            {
                                var resources = module.Resources.Select(r => r.Name).ToArray();
                                Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidEnvironment__"), "AndroidEnvironment EmbeddedResource should be stripped!");
                                Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidLibraryProjects__.zip"), "__AndroidLibraryProjects__.zip should be stripped!");
                                Assert.IsFalse(StringAssertEx.ContainsText(resources, "__AndroidNativeLibraries__.zip"), "__AndroidNativeLibraries__.zip should be stripped!");
                            }
                        }
                    }
                }
        }