Пример #1
0
        public static bool ValidateNdkPlatform(TaskLoggingHelper log, string ndkPath, AndroidTargetArch arch, bool enableLLVM)
        {
            // Check that we have a compatible NDK version for the targeted ABIs.
            NdkUtil.NdkVersion ndkVersion;
            bool hasNdkVersion = NdkUtil.GetNdkToolchainRelease(ndkPath, out ndkVersion);

            if (NdkUtil.IsNdk64BitArch(arch) && hasNdkVersion && ndkVersion.Version < 10)
            {
                log.LogMessage(MessageImportance.High,
                               "The detected Android NDK version is incompatible with the targeted 64-bit architecture, " +
                               "please upgrade to NDK r10 or newer.");
            }

            // NDK r10d is buggy and cannot link x86_64 ABI shared libraries because they are 32-bits.
            // See https://code.google.com/p/android/issues/detail?id=161421
            if (enableLLVM && ndkVersion.Version == 10 && ndkVersion.Revision == "d" && arch == AndroidTargetArch.X86_64)
            {
                log.LogCodedError("XA3004", "Android NDK r10d is buggy and provides an incompatible x86_64 libm.so. " +
                                  "See https://code.google.com/p/android/issues/detail?id=161422.");
                return(false);
            }

            if (enableLLVM && (ndkVersion.Version < 10 || (ndkVersion.Version == 10 && ndkVersion.Revision[0] < 'd')))
            {
                log.LogCodedError("XA3005",
                                  "The detected Android NDK version is incompatible with the targeted LLVM configuration, " +
                                  "please upgrade to NDK r10d or newer.");
            }

            return(true);
        }
Пример #2
0
        static bool ValidateAotConfiguration(TaskLoggingHelper log, AndroidTargetArch arch, bool enableLLVM)
        {
            if (arch == AndroidTargetArch.Arm64 && enableLLVM)
            {
                log.LogCodedError("XA3004", "arm64-v8a architecture is not currently supported on LLVM AOT mode.");
                return(false);
            }

            if (arch == AndroidTargetArch.X86_64)
            {
                log.LogCodedError("XA3004", "x86_64 architecture is not currently supported on AOT mode.");
                return(false);
            }

            return(true);
        }
        public static string TryGetAndroidJarPath(TaskLoggingHelper log, string platform)
        {
            var platformPath = MonoAndroidHelper.AndroidSdk.TryGetPlatformDirectoryFromApiLevel(platform, MonoAndroidHelper.SupportedVersions);

            if (platformPath == null)
            {
                var expectedPath       = MonoAndroidHelper.AndroidSdk.GetPlatformDirectoryFromId(platform);
                var sdkManagerMenuPath = OS.IsWindows ? Properties.Resources.XA5207_SDK_Manager_Windows : Properties.Resources.XA5207_SDK_Manager_macOS;
                log.LogCodedError("XA5207", Properties.Resources.XA5207, platform, Path.Combine(expectedPath, "android.jar"), sdkManagerMenuPath);
                return(null);
            }
            return(Path.Combine(platformPath, "android.jar"));
        }
Пример #4
0
        public static string TryGetAndroidJarPath(TaskLoggingHelper log, string platform)
        {
            var platformPath = MonoAndroidHelper.AndroidSdk.TryGetPlatformDirectoryFromApiLevel(platform, MonoAndroidHelper.SupportedVersions);

            if (platformPath == null)
            {
                var expectedPath = MonoAndroidHelper.AndroidSdk.GetPlatformDirectoryFromId(platform);
                log.LogCodedError("XA5207", "Could not find android.jar for API Level {0}. " +
                                  "This means the Android SDK platform for API Level {0} is not installed. " +
                                  "Either install it in the Android SDK Manager (Tools > Open Android SDK Manager...), " +
                                  "or change your Xamarin.Android project to target an API version that is installed. " +
                                  "({1} missing.)",
                                  platform, Path.Combine(expectedPath, "android.jar"));
                return(null);
            }
            return(Path.Combine(platformPath, "android.jar"));
        }
Пример #5
0
        public static bool Init(TaskLoggingHelper log, string ndkPath)
        {
            Version ndkVersion;
            bool    hasNdkVersion = GetNdkToolchainRelease(ndkPath ?? "", out ndkVersion);

            if (!hasNdkVersion)
            {
                log.LogCodedError("XA5101",
                                  "Could not locate the Android NDK. Please make sure the Android NDK is installed in the Android SDK Manager, " +
                                  "or if using a custom NDK path, please ensure the $(AndroidNdkDirectory) MSBuild property is set to the custom path.");
                return(false);
            }

            usingClangNDK = ndkVersion.Major >= 19;

            return(true);
        }
Пример #6
0
        public static void LogFromStandardError(this TaskLoggingHelper log, string defaultErrorCode, string message)
        {
            if (string.IsNullOrEmpty(message))
            {
                return;
            }

            var m = Message.Match(message);

            if (!m.Success)
            {
                if (message.IndexOf("error:", StringComparison.InvariantCultureIgnoreCase) != -1)
                {
                    log.LogCodedError(defaultErrorCode, message);
                }
                else
                {
                    log.LogMessage(null, defaultErrorCode, null, null, 0, 0, 0, 0, MessageImportance.Low, message);
                }
                return;
            }

            string subcategory = m.Groups["source"].Value;
            string type        = m.Groups["type"].Value;
            string code        = m.Groups["code"].Value;
            string msg         = m.Groups["message"].Value;

            if (string.IsNullOrEmpty(code))
            {
                code = defaultErrorCode;
            }

            if (type == "warning")
            {
                log.LogWarning(subcategory, code, string.Empty, string.Empty, 0, 0, 0, 0, "{0}", msg);
            }
            else
            {
                log.LogError(subcategory, code, string.Empty, string.Empty, 0, 0, 0, 0, "{0}", msg);
            }
        }
Пример #7
0
        public bool Run(Assembly assm, string ResourceName, string OutputPath, TaskLoggingHelper Log)
        {
            // Ensure our output directory exists
            if (!Directory.Exists(Path.GetDirectoryName(OutputPath)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(OutputPath));
            }

            // Copy out one of our embedded resources to a path
            using (var from = GetManifestResourceStream(ResourceName)) {
                if (from == null)
                {
                    Log.LogCodedError("XA0116", $"Unable to find `EmbeddedResource` of name `{ResourceName}`.");
                    return(false);
                }

                // If the resource already exists, only overwrite if it's changed
                if (File.Exists(OutputPath))
                {
                    var hash1 = MonoAndroidHelper.HashFile(OutputPath);
                    var hash2 = MonoAndroidHelper.HashStream(from);

                    if (hash1 == hash2)
                    {
                        Log.LogDebugMessage("Resource {0} is unchanged. Skipping.", OutputPath);
                        return(true);
                    }
                }

                // Hash calculation read to the end, move back to beginning of file
                from.Position = 0;

                // Write out the resource
                using (var to = File.Create(OutputPath))
                    Copy(from, to);

                Log.LogDebugMessage("Wrote resource {0}.", OutputPath);
            }

            return(true);
        }
        public static void LogUnhandledException(this TaskLoggingHelper log, string prefix, Exception ex)
        {
            prefix = "XA" + prefix;

            // Some ordering is necessary here to ensure exceptions are before their base exceptions
            if (ex is NullReferenceException)
            {
                log.LogCodedError(prefix + "7001", ex.ToString());
            }
            else if (ex is ArgumentOutOfRangeException)                 // ArgumentException
            {
                log.LogCodedError(prefix + "7002", ex.ToString());
            }
            else if (ex is ArgumentNullException)                       // ArgumentException
            {
                log.LogCodedError(prefix + "7003", ex.ToString());
            }
            else if (ex is ArgumentException)
            {
                log.LogCodedError(prefix + "7004", ex.ToString());
            }
            else if (ex is FormatException)
            {
                log.LogCodedError(prefix + "7005", ex.ToString());
            }
            else if (ex is IndexOutOfRangeException)
            {
                log.LogCodedError(prefix + "7006", ex.ToString());
            }
            else if (ex is InvalidCastException)
            {
                log.LogCodedError(prefix + "7007", ex.ToString());
            }
            else if (ex is ObjectDisposedException)                     // InvalidOperationException
            {
                log.LogCodedError(prefix + "7008", ex.ToString());
            }
            else if (ex is InvalidOperationException)
            {
                log.LogCodedError(prefix + "7009", ex.ToString());
            }
            else if (ex is InvalidProgramException)
            {
                log.LogCodedError(prefix + "7010", ex.ToString());
            }
            else if (ex is KeyNotFoundException)
            {
                log.LogCodedError(prefix + "7011", ex.ToString());
            }
            else if (ex is TaskCanceledException)                       // OperationCanceledException
            {
                log.LogCodedError(prefix + "7012", ex.ToString());
            }
            else if (ex is OperationCanceledException)
            {
                log.LogCodedError(prefix + "7013", ex.ToString());
            }
            else if (ex is OutOfMemoryException)
            {
                log.LogCodedError(prefix + "7014", ex.ToString());
            }
            else if (ex is NotSupportedException)
            {
                log.LogCodedError(prefix + "7015", ex.ToString());
            }
            else if (ex is StackOverflowException)
            {
                log.LogCodedError(prefix + "7016", ex.ToString());
            }
            else if (ex is TimeoutException)
            {
                log.LogCodedError(prefix + "7017", ex.ToString());
            }
            else if (ex is TypeInitializationException)
            {
                log.LogCodedError(prefix + "7018", ex.ToString());
            }
            else if (ex is UnauthorizedAccessException)
            {
                log.LogCodedError(prefix + "7019", ex.ToString());
            }
            else if (ex is ApplicationException)
            {
                log.LogCodedError(prefix + "7020", ex.ToString());
            }
            else if (ex is KeyNotFoundException)
            {
                log.LogCodedError(prefix + "7021", ex.ToString());
            }
            else if (ex is PathTooLongException)                        // IOException
            {
                log.LogCodedError(prefix + "7022", ex.ToString());
            }
            else if (ex is DirectoryNotFoundException)                  // IOException
            {
                log.LogCodedError(prefix + "7023", ex.ToString());
            }
            else if (ex is DriveNotFoundException)                      // IOException
            {
                log.LogCodedError(prefix + "7025", ex.ToString());
            }
            else if (ex is EndOfStreamException)                        // IOException
            {
                log.LogCodedError(prefix + "7026", ex.ToString());
            }
            else if (ex is FileLoadException)                           // IOException
            {
                log.LogCodedError(prefix + "7027", ex.ToString());
            }
            else if (ex is FileNotFoundException)                       // IOException
            {
                log.LogCodedError(prefix + "7028", ex.ToString());
            }
            else if (ex is PipeException)                               // IOException
            {
                log.LogCodedError(prefix + "7029", ex.ToString());
            }
            else if (ex is IOException)
            {
                log.LogCodedError(prefix + "7024", ex.ToString());
            }

            log.LogCodedError(prefix + "7000", ex.ToString());
        }
Пример #9
0
        public static void FixupResourceFilenameAndLogCodedError(this TaskLoggingHelper log, string code, string message, string file, string resourceDir, Dictionary <string, string> resourceNameCaseMap)
        {
            var targetfile = FixupResourceFilename(file, resourceDir, resourceNameCaseMap);

            log.LogCodedError(code, file: targetfile, lineNumber: 0, message: message);
        }
Пример #10
0
 public static bool ValidateNdkPlatform(TaskLoggingHelper log, string ndkPath, AndroidTargetArch arch, bool enableLLVM)
 {
     return(ValidateNdkPlatform((m) => log.LogMessage(m), (c, m) => log.LogCodedError(c, m), ndkPath, arch, enableLLVM));
 }
Пример #11
0
 public static bool Init(TaskLoggingHelper log, string ndkPath) =>
 Init((c, m) => log.LogCodedError(c, m), ndkPath);
 public static void LogUnhandledException(this TaskLoggingHelper log, string prefix, Exception ex)
 {
     LogUnhandledException((code, message) => log.LogCodedError(code, message), prefix, ex);
 }
Пример #13
0
        public IList <string> Merge(List <TypeDefinition> subclasses, string applicationClass, bool embed, string bundledWearApplicationName, IEnumerable <string> mergedManifestDocuments)
        {
            string applicationName = ApplicationName;

            var manifest = doc.Root;

            if (manifest == null || manifest.Name != "manifest")
            {
                throw new Exception("Root element must be 'manifest'");
            }

            var manifest_package = (string)manifest.Attribute("package");

            if (!string.IsNullOrWhiteSpace(manifest_package))
            {
                PackageName = manifest_package;
            }

            manifest.SetAttributeValue(XNamespace.Xmlns + "android", "http://schemas.android.com/apk/res/android");
            if (manifest.Attribute(androidNs + "versionCode") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionCode", "1");
            }
            if (manifest.Attribute(androidNs + "versionName") == null)
            {
                manifest.SetAttributeValue(androidNs + "versionName", "1.0");
            }

            app = CreateApplicationElement(manifest, applicationClass, subclasses);

            if (app.Attribute(androidNs + "label") == null && applicationName != null)
            {
                app.SetAttributeValue(androidNs + "label", applicationName);
            }

            var existingTypes = new HashSet <string> (
                app.Descendants().Select(a => (string)a.Attribute(attName)).Where(v => v != null));

            if (!string.IsNullOrEmpty(bundledWearApplicationName))
            {
                if (!app.Elements("meta-data").Any(e => e.Attributes(androidNs + "name").Any(a => a.Value == bundledWearApplicationName)))
                {
                    app.Add(new XElement("meta-data", new XAttribute(androidNs + "name", "com.google.android.wearable.beta.app"), new XAttribute(androidNs + "resource", "@xml/wearable_app_desc")));
                }
            }

            // If no <uses-sdk> is specified, add it with both minSdkVersion and
            // targetSdkVersion set to TargetFrameworkVersion
            if (!manifest.Elements("uses-sdk").Any())
            {
                manifest.AddFirst(
                    new XElement("uses-sdk",
                                 new XAttribute(androidNs + "minSdkVersion", SdkVersionName),
                                 new XAttribute(androidNs + "targetSdkVersion", SdkVersionName)));
            }

            // If no minSdkVersion is specified, set it to TargetFrameworkVersion
            var uses = manifest.Element("uses-sdk");

            if (uses.Attribute(androidNs + "minSdkVersion") == null)
            {
                int minSdkVersion;
                if (!int.TryParse(SdkVersionName, out minSdkVersion))
                {
                    minSdkVersion = XABuildConfig.NDKMinimumApiAvailable;
                }
                minSdkVersion = Math.Min(minSdkVersion, XABuildConfig.NDKMinimumApiAvailable);
                uses.SetAttributeValue(androidNs + "minSdkVersion", minSdkVersion.ToString());
            }

            string targetSdkVersion;
            var    tsv = uses.Attribute(androidNs + "targetSdkVersion");

            if (tsv != null)
            {
                targetSdkVersion = tsv.Value;
            }
            else
            {
                targetSdkVersion = SdkVersionName;
                uses.AddBeforeSelf(new XComment("suppress UsesMinSdkAttributes"));
            }

            int?tryTargetSdkVersion = MonoAndroidHelper.SupportedVersions.GetApiLevelFromId(targetSdkVersion);

            if (!tryTargetSdkVersion.HasValue)
            {
                throw new InvalidOperationException(string.Format("The targetSdkVersion ({0}) is not a valid API level", targetSdkVersion));
            }
            int targetSdkVersionValue = tryTargetSdkVersion.Value;

            foreach (var t in subclasses)
            {
                if (t.IsAbstract)
                {
                    continue;
                }

                if (PackageName == null)
                {
                    PackageName = t.Namespace;
                }

                var name       = JavaNativeTypeManager.ToJniName(t).Replace('/', '.');
                var compatName = JavaNativeTypeManager.ToCompatJniName(t).Replace('/', '.');
                if (((string)app.Attribute(attName)) == compatName)
                {
                    app.SetAttributeValue(attName, name);
                }

                Func <TypeDefinition, string, int, XElement> generator = GetGenerator(t);
                if (generator == null)
                {
                    continue;
                }

                try {
                    // activity not present: create a launcher for it IFF it has attribute
                    if (!existingTypes.Contains(name) && !existingTypes.Contains(compatName))
                    {
                        XElement fromCode = generator(t, name, targetSdkVersionValue);
                        if (fromCode == null)
                        {
                            continue;
                        }

                        IEnumerable <MethodDefinition> constructors = t.Methods.Where(m => m.IsConstructor).Cast <MethodDefinition> ();
                        if (!constructors.Any(c => !c.HasParameters && c.IsPublic))
                        {
                            string        message        = $"The type '{t.FullName}' must provide a public default constructor";
                            SequencePoint sourceLocation = FindSource(constructors);

                            if (sourceLocation != null && sourceLocation.Document?.Url != null)
                            {
                                log.LogError(
                                    subcategory:      String.Empty,
                                    errorCode:        "XA4213",
                                    helpKeyword:      String.Empty,
                                    file:             sourceLocation.Document.Url,
                                    lineNumber:       sourceLocation.StartLine,
                                    columnNumber:     sourceLocation.StartColumn,
                                    endLineNumber:    sourceLocation.EndLine,
                                    endColumnNumber:  sourceLocation.EndColumn,
                                    message:          message);
                            }
                            else
                            {
                                log.LogCodedError("XA4213", message);
                            }
                            continue;
                        }
                        app.Add(fromCode);
                    }
                    foreach (var d in app.Descendants().Where(a => ((string)a.Attribute(attName)) == compatName))
                    {
                        d.SetAttributeValue(attName, name);
                    }
                } catch (InvalidActivityNameException ex) {
                    log.LogErrorFromException(ex);
                }
            }

            var icon = app.Attribute(androidNs + "icon");

            if (icon == null)
            {
                var activity = app.Element("activity");
                if (activity != null)
                {
                    var activityIcon = activity.Attribute(androidNs + "icon");
                    if (activityIcon != null)
                    {
                        app.Add(new XAttribute(androidNs + "icon", activityIcon.Value));
                    }
                }
            }

            PackageName = AndroidAppManifest.CanonicalizePackageName(PackageName);

            if (!PackageName.Contains('.'))
            {
                throw new InvalidOperationException("/manifest/@package attribute MUST contain a period ('.').");
            }

            manifest.SetAttributeValue("package", PackageName);

            if (MultiDex)
            {
                app.Add(CreateMonoRuntimeProvider("mono.android.MultiDexLoader", null, initOrder: --AppInitOrder));
            }

            var providerNames = AddMonoRuntimeProviders(app);

            if (Debug && !embed && InstantRunEnabled)
            {
                if (int.TryParse(SdkVersion, out int apiLevel) && apiLevel >= 19)
                {
                    app.Add(CreateMonoRuntimeProvider("mono.android.ResourcePatcher", null, initOrder: --AppInitOrder));
                }
            }
            if (Debug)
            {
                app.Add(new XComment("suppress ExportedReceiver"));
                app.Add(new XElement("receiver",
                                     new XAttribute(androidNs + "name", "mono.android.Seppuku"),
                                     new XElement("intent-filter",
                                                  new XElement("action",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.action.SEPPUKU")),
                                                  new XElement("category",
                                                               new XAttribute(androidNs + "name", "mono.android.intent.category.SEPPUKU." + PackageName)))));
                if (app.Attribute(androidNs + "debuggable") == null)
                {
                    app.Add(new XAttribute(androidNs + "debuggable", "true"));
                }
            }
            if (Debug || NeedsInternet)
            {
                AddInternetPermissionForDebugger();
            }

            if (!embed)
            {
                AddFastDeployPermissions();
            }

            // If the manifest has android:installLocation, but we are targeting
            // API 7 or lower, remove it for the user and show a warning
            if (manifest.Attribute(androidNs + "installLocation") != null)
            {
                if (targetSdkVersionValue < 8)
                {
                    manifest.Attribute(androidNs + "installLocation").Remove();
                    Console.Error.WriteLine("monodroid: warning 1 : installLocation cannot be specified for Android versions less than 2.2.  Attribute installLocation ignored.");
                }
            }

            AddInstrumentations(manifest, subclasses, targetSdkVersionValue);
            AddPermissions(app);
            AddPermissionGroups(app);
            AddPermissionTrees(app);
            AddUsesPermissions(app);
            AddUsesFeatures(app);
            AddSupportsGLTextures(app);

            ReorderActivityAliases(app);
            ReorderElements(app);

            if (mergedManifestDocuments != null)
            {
                foreach (var mergedManifest in mergedManifestDocuments)
                {
                    try {
                        MergeLibraryManifest(mergedManifest);
                    } catch (Exception ex) {
                        log.LogCodedWarning("XA4302", "Unhandled exception merging `AndroidManifest.xml`: {0}", ex);
                    }
                }
            }

            return(providerNames);

            SequencePoint FindSource(IEnumerable <MethodDefinition> methods)
            {
                if (methods == null)
                {
                    return(null);
                }

                SequencePoint ret = null;

                foreach (MethodDefinition method in methods.Where(m => m != null && m.HasBody && m.DebugInformation != null))
                {
                    foreach (Instruction ins in method.Body.Instructions)
                    {
                        SequencePoint seq = method.DebugInformation.GetSequencePoint(ins);
                        if (seq == null)
                        {
                            continue;
                        }

                        if (ret == null || seq.StartLine < ret.StartLine)
                        {
                            ret = seq;
                        }
                        break;
                    }
                }

                return(ret);
            }
        }