Skip to content

Commit

Permalink
Soo.... Android, yes.
Browse files Browse the repository at this point in the history
After a few months of names like `arc.so.bin` or `#Assembly.dll.so` or
`assemblies.arm64-v8a.blob.so` working just fine, Android 14 (on Pixel
6) stopped extracting entries with such names to the filesystem when the
`extractNativeLibs` flag is set to `true` in the manifest.  Not only
"special" characters (tested `#`, `!`, `~`, `@`, `%` and then gave up)
are no longer accepted - `lib/{ARCH]` entries with them are ignored and
not extracted to the file system, but also any entries without the `lib`
prefix are ignored (but ONLY on Release builds).

So, the new mangling style is:

  * `lib_` prefix for regular assemblies
  * `lib-culture-` prefix for satellite assemblies.

Also, all the entries we place in `lib` are now compressed, as per the
build mode.

Let's see which tests break now.
  • Loading branch information
grendello committed Jan 31, 2024
1 parent 5a6d37f commit d706ffe
Show file tree
Hide file tree
Showing 14 changed files with 209 additions and 141 deletions.
16 changes: 8 additions & 8 deletions src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,8 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And
foreach (string abi in SupportedAbis) {
// Prefix it with `a` because bundletool sorts entries alphabetically, and this will place it right next to `assemblies.*.blob.so`, which is what we
// like since we can finish scanning the zip central directory earlier at startup.
inArchivePath = MakeArchiveLibPath (abi, "arc.bin.so");
AddFileToArchiveIfNewer (apk, RuntimeConfigBinFilePath, inArchivePath, compressionMethod: UncompressedMethod);
inArchivePath = MakeArchiveLibPath (abi, "libarc.bin.so");
AddFileToArchiveIfNewer (apk, RuntimeConfigBinFilePath, inArchivePath, compressionMethod: GetCompressionMethod (inArchivePath));
}
}

Expand All @@ -442,8 +442,8 @@ void AddAssemblies (ZipArchiveEx apk, bool debug, bool compress, IDictionary<And

foreach (var kvp in assemblyStorePaths) {
string abi = MonoAndroidHelper.ArchToAbi (kvp.Key);
inArchivePath = MakeArchiveLibPath (abi, Path.GetFileName (kvp.Value));
AddFileToArchiveIfNewer (apk, kvp.Value, inArchivePath, UncompressedMethod);
inArchivePath = MakeArchiveLibPath (abi, "lib" + Path.GetFileName (kvp.Value));
AddFileToArchiveIfNewer (apk, kvp.Value, inArchivePath, GetCompressionMethod (inArchivePath));
}

void AddAssembliesFromCollection (ITaskItem[] assemblies)
Expand Down Expand Up @@ -649,14 +649,14 @@ void AddAssemblyConfigEntry (ZipArchiveEx apk, string assemblyPath, string confi
// All of the assemblies have their names mangled so that the possibility to clash with "real" shared
// library names is minimized. All of the assembly entries will start with a special character:
//
// # - for regular assemblies (e.g. `#Mono.Android.dll.so`)
// % - for satellite assemblies (e.g. `%es%Mono.Android.dll.so`)
// `_` - for regular assemblies (e.g. `_Mono.Android.dll.so`)
// `-` - for satellite assemblies (e.g. `-es-Mono.Android.dll.so`)
//
// Second of all, we need to treat satellite assemblies with even more care.
// If we encounter one of them, we will return the culture as part of the path transformed
// so that it forms a `%culture%` assembly file name prefix, not a `culture/` subdirectory.
// so that it forms a `-culture-` assembly file name prefix, not a `culture/` subdirectory.
// This is necessary because Android doesn't allow subdirectories in `lib/{ABI}/`

//
string[] subdirParts = subDirectory.TrimEnd ('/').Split ('/');
if (subdirParts.Length == 1) {
// Not a satellite assembly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblySto
"System.Collections.dll",
"System.Collections.Concurrent.dll",
"System.Text.RegularExpressions.dll",
"arc.bin.so",
"libarc.bin.so",
};

using (var b = CreateApkBuilder ()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,16 @@ public int GetNumberOfAssemblies (bool forceRefresh = false, AndroidTargetArch a
{
List<string> contents = ListArchiveContents (assembliesRootDir, forceRefresh, arch);

// We must count only .dll.so entries starting with the '#' character, as they are the actual managed assemblies.
// We must count only .dll.so entries starting with the '-' and '_' characters, as they are the actual managed assemblies.
// Other entries in `lib/{arch}` might be AOT shared libraries, which will also have the .dll.so extension.
var dlls = contents.Where (x => {
string fileName = Path.GetFileName (x);
return fileName[0] == '#' && fileName.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase);
if (!fileName.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase)) {
return false;
}
return fileName.StartsWith (MonoAndroidHelper.MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER, StringComparison.OrdinalIgnoreCase) ||
fileName.StartsWith (MonoAndroidHelper.MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER, StringComparison.OrdinalIgnoreCase);
});

return dlls.Count ();
Expand Down Expand Up @@ -319,7 +324,7 @@ public int GetNumberOfAssemblies (bool forceRefresh = false, AndroidTargetArch a
break;
}

char fileTypeMarker = '#';
string fileTypeMarker = MonoAndroidHelper.MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER;
var abis = new List<string> ();
if (!String.IsNullOrEmpty (abi)) {
abis.Add (abi);
Expand All @@ -334,8 +339,8 @@ public int GetNumberOfAssemblies (bool forceRefresh = false, AndroidTargetArch a
if (!String.IsNullOrEmpty (culture)) {
// Android doesn't allow us to put satellite assemblies in lib/{CULTURE}/assembly.dll.so, we must instead
// mangle the name.
fileName = $"{culture}%{fileName}";
fileTypeMarker = '%';
fileTypeMarker = MonoAndroidHelper.MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER;
fileName = $"{culture}{fileTypeMarker}-{fileName}";
}

var ret = new List<string> ();
Expand Down Expand Up @@ -479,23 +484,6 @@ IEnumerable<string> GetAdditionalFilesForAbi (string abi, List<string> existingF
(string prefixAssemblies, string prefixLib) = GetArchivePrefixes (abi);
return existingFiles.Where (x => !fileNames.Contains (x.Replace (prefixAssemblies, string.Empty)) && !fileNames.Contains (x.Replace (prefixLib, String.Empty)));
}

string GetUnmangledFileName (string fullName)
{
string fileName = Path.GetFileName (fullName);
switch(fileName[0]) {
case '#':
// Drop the '#' prefix and the .so extension
return Path.GetFileNameWithoutExtension (fileName.Substring (1));

case '%':
// Drop the '%' prefix, replace the following '%s' with `/` to get a culture/Assembly file name and drop the .so extension
return Path.GetFileNameWithoutExtension (fileName.Substring (1).Replace ('%', '/'));

default:
return fileName;
}
}
}

void StoreContains (ICollection<string> fileNames, out List<string> existingFiles, out List<string> missingFiles, out List<string> additionalFiles, IEnumerable<AndroidTargetArch>? targetArches = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,37 @@
"classes.dex": {
"Size": 377856
},
"lib/arm64-v8a/#_Microsoft.Android.Resource.Designer.dll.so": {
"lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": {
"Size": 1027
},
"lib/arm64-v8a/#Java.Interop.dll.so": {
"lib/arm64-v8a/lib_Java.Interop.dll.so": {
"Size": 61443
},
"lib/arm64-v8a/#Mono.Android.dll.so": {
"lib/arm64-v8a/lib_Mono.Android.dll.so": {
"Size": 90421
},
"lib/arm64-v8a/#Mono.Android.Runtime.dll.so": {
"lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": {
"Size": 5143
},
"lib/arm64-v8a/#System.Console.dll.so": {
"lib/arm64-v8a/lib_System.Console.dll.so": {
"Size": 6537
},
"lib/arm64-v8a/#System.Linq.dll.so": {
"lib/arm64-v8a/lib_System.Linq.dll.so": {
"Size": 8540
},
"lib/arm64-v8a/#System.Private.CoreLib.dll.so": {
"lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": {
"Size": 552396
},
"lib/arm64-v8a/#System.Runtime.dll.so": {
"lib/arm64-v8a/lib_System.Runtime.dll.so": {
"Size": 2541
},
"lib/arm64-v8a/#System.Runtime.InteropServices.dll.so": {
"lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": {
"Size": 4019
},
"lib/arm64-v8a/#UnnamedProject.dll.so": {
"lib/arm64-v8a/lib_UnnamedProject.dll.so": {
"Size": 2931
},
"lib/arm64-v8a/arc.bin.so": {
"lib/arm64-v8a/libarc.bin.so": {
"Size": 1512
},
"lib/arm64-v8a/libmono-component-marshal-ilgen.so": {
Expand Down
Loading

0 comments on commit d706ffe

Please sign in to comment.