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); }
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); }
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); }
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"); } } } } }