Beispiel #1
0
        uint WriteDescriptor(StreamWriter output, string assemblyName, CompressedAssemblyInfo info, string dataLabel)
        {
            WriteCommentLine(output, $"{info.DescriptorIndex}: {assemblyName}");

            WriteCommentLine(output, "uncompressed_file_size");
            uint size = WriteData(output, info.FileSize);

            WriteCommentLine(output, "loaded");
            size += WriteData(output, false);

            WriteCommentLine(output, "data");
            size += WritePointer(output, dataLabel);

            output.WriteLine();
            return(size);
        }
Beispiel #2
0
        public override bool RunTask()
        {
            Aot.TryGetSequencePointsMode(AndroidSequencePointsMode, out sequencePointsMode);

            var outputFiles = new List <string> ();

            uncompressedFileExtensions = UncompressedFileExtensions?.Split(new char [] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries) ?? new string [0];

            existingEntries.Clear();

            bool debug    = _Debug;
            bool compress = !debug && EnableCompression;
            IDictionary <string, CompressedAssemblyInfo> compressedAssembliesInfo = null;

            if (compress)
            {
                string key = CompressedAssemblyInfo.GetKey(ProjectFullPath);
                Log.LogDebugMessage($"Retrieving assembly compression info with key '{key}'");
                compressedAssembliesInfo = BuildEngine4.UnregisterTaskObjectAssemblyLocal <IDictionary <string, CompressedAssemblyInfo> > (key, RegisteredTaskObjectLifetime.Build);
                if (compressedAssembliesInfo == null)
                {
                    throw new InvalidOperationException($"Assembly compression info not found for key '{key}'. Compression will not be performed.");
                }
            }

            ExecuteWithAbi(SupportedAbis, ApkInputPath, ApkOutputPath, debug, compress, compressedAssembliesInfo);
            outputFiles.Add(ApkOutputPath);
            if (CreatePackagePerAbi && SupportedAbis.Length > 1)
            {
                foreach (var abi in SupportedAbis)
                {
                    existingEntries.Clear();
                    var path = Path.GetDirectoryName(ApkOutputPath);
                    var apk  = Path.GetFileNameWithoutExtension(ApkOutputPath);
                    ExecuteWithAbi(new [] { abi }, String.Format("{0}-{1}", ApkInputPath, abi),
                                   Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi)),
                                   debug, compress, compressedAssembliesInfo);
                    outputFiles.Add(Path.Combine(path, String.Format("{0}-{1}.apk", apk, abi)));
                }
            }

            OutputFiles = outputFiles.Select(a => new TaskItem(a)).ToArray();

            Log.LogDebugTaskItems("  [Output] OutputFiles :", OutputFiles);

            return(!Log.HasLoggedErrors);
        }
Beispiel #3
0
        protected override void WriteSymbols(StreamWriter output)
        {
            if (assemblies == null || assemblies.Count == 0)
            {
                WriteCompressedAssembliesStructure(output, 0, null);
                return;
            }

            string label = MakeLocalLabel(DescriptorsField);

            using (var dataOutput = MemoryStreamPool.Shared.CreateStreamWriter(output.Encoding)) {
                uint size = 0;

                output.Write(Indent);
                output.Write(".include");
                output.Write(Indent);
                output.Write('"');
                output.Write(Path.GetFileName(dataIncludeFile));
                output.WriteLine('"');
                output.WriteLine();

                WriteDataSection(output, DescriptorsField);
                WriteStructureSymbol(output, label, alignBits: TargetProvider.MapModulesAlignBits, isGlobal: false);
                foreach (var kvp in assemblies)
                {
                    string assemblyName         = kvp.Key;
                    CompressedAssemblyInfo info = kvp.Value;

                    string dataLabel = GetAssemblyDataLabel(info.DescriptorIndex);
                    WriteCommSymbol(dataOutput, dataLabel, info.FileSize, 16);
                    dataOutput.WriteLine();

                    size += WriteStructure(output, packed: false, structureWriter: () => WriteDescriptor(output, assemblyName, info, dataLabel));
                }
                WriteStructureSize(output, label, size);

                dataOutput.Flush();
                Files.CopyIfStreamChanged(dataOutput.BaseStream, dataIncludeFile);
            }

            WriteCompressedAssembliesStructure(output, (uint)assemblies.Count, label);
        }
Beispiel #4
0
        void AddAssemblies(ZipArchiveEx apk, bool debug, bool compress, IDictionary <string, CompressedAssemblyInfo> compressedAssembliesInfo)
        {
            string sourcePath;

            AssemblyCompression.AssemblyData compressedAssembly = null;
            string compressedOutputDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(ApkOutputPath), "..", "lz4"));

            int count = 0;

            foreach (ITaskItem assembly in ResolvedUserAssemblies)
            {
                if (bool.TryParse(assembly.GetMetadata("AndroidSkipAddToPackage"), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping {assembly.ItemSpec} due to 'AndroidSkipAddToPackage' == 'true' ");
                    continue;
                }
                if (MonoAndroidHelper.IsReferenceAssembly(assembly.ItemSpec))
                {
                    Log.LogCodedWarning("XA0107", assembly.ItemSpec, 0, Properties.Resources.XA0107, assembly.ItemSpec);
                }

                sourcePath = CompressAssembly(assembly);

                // Add assembly
                var assemblyPath = GetAssemblyPath(assembly, frameworkAssembly: false);
                AddFileToArchiveIfNewer(apk, sourcePath, assemblyPath + Path.GetFileName(assembly.ItemSpec), compressionMethod: UncompressedMethod);

                // Try to add config if exists
                var config = Path.ChangeExtension(assembly.ItemSpec, "dll.config");
                AddAssemblyConfigEntry(apk, assemblyPath, config);

                // Try to add symbols if Debug
                if (debug)
                {
                    var symbols = Path.ChangeExtension(assembly.ItemSpec, "dll.mdb");

                    if (File.Exists(symbols))
                    {
                        AddFileToArchiveIfNewer(apk, symbols, assemblyPath + Path.GetFileName(symbols), compressionMethod: UncompressedMethod);
                    }

                    symbols = Path.ChangeExtension(assembly.ItemSpec, "pdb");

                    if (File.Exists(symbols))
                    {
                        AddFileToArchiveIfNewer(apk, symbols, assemblyPath + Path.GetFileName(symbols), compressionMethod: UncompressedMethod);
                    }
                }
                count++;
                if (count >= ZipArchiveEx.ZipFlushFilesLimit)
                {
                    apk.Flush();
                    count = 0;
                }
            }

            count = 0;
            // Add framework assemblies
            foreach (ITaskItem assembly in ResolvedFrameworkAssemblies)
            {
                if (bool.TryParse(assembly.GetMetadata("AndroidSkipAddToPackage"), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping {assembly.ItemSpec} due to 'AndroidSkipAddToPackage' == 'true' ");
                    continue;
                }

                if (MonoAndroidHelper.IsReferenceAssembly(assembly.ItemSpec))
                {
                    Log.LogCodedWarning("XA0107", assembly.ItemSpec, 0, Properties.Resources.XA0107, assembly.ItemSpec);
                }

                sourcePath = CompressAssembly(assembly);
                var assemblyPath = GetAssemblyPath(assembly, frameworkAssembly: true);
                AddFileToArchiveIfNewer(apk, sourcePath, assemblyPath + Path.GetFileName(assembly.ItemSpec), compressionMethod: UncompressedMethod);
                var config = Path.ChangeExtension(assembly.ItemSpec, "dll.config");
                AddAssemblyConfigEntry(apk, assemblyPath, config);
                // Try to add symbols if Debug
                if (debug)
                {
                    var symbols = Path.ChangeExtension(assembly.ItemSpec, "dll.mdb");

                    if (File.Exists(symbols))
                    {
                        AddFileToArchiveIfNewer(apk, symbols, assemblyPath + Path.GetFileName(symbols), compressionMethod: UncompressedMethod);
                    }

                    symbols = Path.ChangeExtension(assembly.ItemSpec, "pdb");

                    if (File.Exists(symbols))
                    {
                        AddFileToArchiveIfNewer(apk, symbols, assemblyPath + Path.GetFileName(symbols), compressionMethod: UncompressedMethod);
                    }
                }
                count++;
                if (count >= ZipArchiveEx.ZipFlushFilesLimit)
                {
                    apk.Flush();
                    count = 0;
                }
            }

            void EnsureCompressedAssemblyData(string sourcePath, uint descriptorIndex)
            {
                if (compressedAssembly == null)
                {
                    compressedAssembly = new AssemblyCompression.AssemblyData(sourcePath, descriptorIndex);
                }
                else
                {
                    compressedAssembly.SetData(sourcePath, descriptorIndex);
                }
            }

            string CompressAssembly(ITaskItem assembly)
            {
                if (!compress)
                {
                    return(assembly.ItemSpec);
                }

                if (bool.TryParse(assembly.GetMetadata("AndroidSkipCompression"), out bool value) && value)
                {
                    Log.LogDebugMessage($"Skipping compression of {assembly.ItemSpec} due to 'AndroidSkipCompression' == 'true' ");
                    return(assembly.ItemSpec);
                }

                var key = CompressedAssemblyInfo.GetDictionaryKey(assembly);

                if (compressedAssembliesInfo.TryGetValue(key, out CompressedAssemblyInfo info) && info != null)
                {
                    EnsureCompressedAssemblyData(assembly.ItemSpec, info.DescriptorIndex);
                    string assemblyOutputDir;
                    string subDirectory = assembly.GetMetadata("DestinationSubDirectory");
                    if (!String.IsNullOrEmpty(subDirectory))
                    {
                        assemblyOutputDir = Path.Combine(compressedOutputDir, subDirectory);
                    }
                    else
                    {
                        assemblyOutputDir = compressedOutputDir;
                    }
                    AssemblyCompression.CompressionResult result = AssemblyCompression.Compress(compressedAssembly, assemblyOutputDir);
                    if (result != AssemblyCompression.CompressionResult.Success)
                    {
                        switch (result)
                        {
                        case AssemblyCompression.CompressionResult.EncodingFailed:
                            Log.LogMessage($"Failed to compress {assembly.ItemSpec}");
                            break;

                        case AssemblyCompression.CompressionResult.InputTooBig:
                            Log.LogMessage($"Input assembly {assembly.ItemSpec} exceeds maximum input size");
                            break;

                        default:
                            Log.LogMessage($"Unknown error compressing {assembly.ItemSpec}");
                            break;
                        }
                        return(assembly.ItemSpec);
                    }
                    return(compressedAssembly.DestinationPath);
                }
                else
                {
                    Log.LogDebugMessage($"Assembly missing from {nameof (CompressedAssemblyInfo)}: {key}");
                }

                return(assembly.ItemSpec);
            }
        }
        void GenerateCompressedAssemblySources()
        {
            if (Debug || !EnableCompression)
            {
                Generate(null);
                return;
            }

            var assemblies = new SortedDictionary <string, CompressedAssemblyInfo> (StringComparer.Ordinal);

            foreach (ITaskItem assembly in ResolvedAssemblies)
            {
                if (bool.TryParse(assembly.GetMetadata("AndroidSkipAddToPackage"), out bool value) && value)
                {
                    continue;
                }

                if (assemblies.ContainsKey(assembly.ItemSpec))
                {
                    continue;
                }

                var fi = new FileInfo(assembly.ItemSpec);
                if (!fi.Exists)
                {
                    Log.LogError($"Assembly {assembly.ItemSpec} does not exist");
                    continue;
                }

                assemblies.Add(CompressedAssemblyInfo.GetDictionaryKey(assembly),
                               new CompressedAssemblyInfo(checked ((uint)fi.Length)));
            }

            uint index = 0;

            foreach (var kvp in assemblies)
            {
                kvp.Value.DescriptorIndex = index++;
            }

            string key = CompressedAssemblyInfo.GetKey(ProjectFullPath);

            Log.LogDebugMessage($"Storing compression assemblies info with key '{key}'");
            BuildEngine4.RegisterTaskObjectAssemblyLocal(key, assemblies, RegisteredTaskObjectLifetime.Build);
            Generate(assemblies);

            void Generate(IDictionary <string, CompressedAssemblyInfo> dict)
            {
                foreach (string abi in SupportedAbis)
                {
                    NativeAssemblerTargetProvider asmTargetProvider = GeneratePackageManagerJava.GetAssemblyTargetProvider(abi);
                    string baseAsmFilePath = Path.Combine(EnvironmentOutputDirectory, $"compressed_assemblies.{abi.ToLowerInvariant ()}");
                    string asmFilePath     = $"{baseAsmFilePath}.s";
                    var    asmgen          = new CompressedAssembliesNativeAssemblyGenerator(dict, asmTargetProvider, baseAsmFilePath);

                    using (var sw = MemoryStreamPool.Shared.CreateStreamWriter()) {
                        asmgen.Write(sw);
                        sw.Flush();
                        if (MonoAndroidHelper.CopyIfStreamChanged(sw.BaseStream, asmFilePath))
                        {
                            Log.LogDebugMessage($"File {asmFilePath} was regenerated");
                        }
                    }
                }
            }
        }