Skip to content

Commit 4b20432

Browse files
grendellojonpryor
authored andcommitted
[native/monodroid] Fix unmangling of satellite assembly names (#9533)
Fixes: #9532 Context: #9410 Context: 86260ed Context: c927026 In Debug configuration builds, `$(EmbedAssembliesIntoApk)`=false by default. This enables Fast Deployment in commercial/non-OSS builds. When `$(EmbedAssembliesIntoApk)`=true, there are two separate ways to embed assemblies into the `.apk`: * Assembly Stores (c927026), which is a "single" (-ish) file that contains multiple assemblies, enabled by setting `$(AndroidUseAssemblyStore)`=true. This is the default behavior for Release configuration builds. * One file per assembly (86260ed). This is the default behavior for Debug configuration builds when `$(EmbedAssembliesIntoApk)`=true. Aside: #9410 is an attempt to *remove* support for the "one file per assembly" packaging strategy, which will *not* be applied to release/9.0.1xx. When using the "one file per assembly" strategy, all the assemblies are wrapped in a valid ELF shared library image and placed in the `lib/{ABI}` directories inside the APK/AAB archive. Since those directories don't support subdirectories, we need to encode satellite assembly culture in a way that doesn't use the `/` directory separator char. This encoding, as originally implemented, unfortunately used the `-` character which made it ambiguous with culture names that consist of two parts, e.g. `de-DE`, since the unmangling process would look for the first occurrence of `-` to replace it with `/`, which would form invalid assembly names such as `de/DE-MyAssembly.resources.dll` instead of the correct `de-DE/MyAssembly.resources.dll`. This would, eventually, lead to a mismatch when looking for satellite assembly for that specific culture. Fix it by changing the encoding for `/` from `-` to `_`, so that the mangled assembly name looks like `lib_de-DE_MyAssembly.resources.dll.so` and we can unambiguously decode it to the correct `de-DE/MyAssembly.resources.dll` name.
1 parent 96b0a73 commit 4b20432

File tree

6 files changed

+14
-7
lines changed

6 files changed

+14
-7
lines changed

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo
5050
new BuildItem ("EmbeddedResource", "Resource.es.resx") {
5151
TextContent = () => InlineData.ResxWithContents ("<data name=\"CancelButton\"><value>Cancelar</value></data>")
5252
},
53+
new BuildItem ("EmbeddedResource", "Resource.de-DE.resx") {
54+
TextContent = () => InlineData.ResxWithContents ("<data name=\"CancelButton\"><value>Abbrechen</value></data>")
55+
},
5356
new AndroidItem.TransformFile ("Transforms.xml") {
5457
// Remove two methods that introduced warnings:
5558
// Com.Balysv.Material.Drawable.Menu.MaterialMenuView.cs(214,30): warning CS0114: 'MaterialMenuView.OnRestoreInstanceState(IParcelable)' hides inherited member 'View.OnRestoreInstanceState(IParcelable?)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
@@ -114,6 +117,7 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo
114117
.ToArray ();
115118
var expectedFiles = new List<string> {
116119
$"{proj.PackageName}-Signed.apk",
120+
"de-DE",
117121
"es",
118122
$"{proj.ProjectName}.dll",
119123
$"{proj.ProjectName}.pdb",
@@ -163,6 +167,7 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease, bool aot, bo
163167
helper.AssertContainsEntry ($"assemblies/{proj.ProjectName}.pdb", shouldContainEntry: !TestEnvironment.CommercialBuildAvailable && !isRelease);
164168
helper.AssertContainsEntry ($"assemblies/Mono.Android.dll", shouldContainEntry: expectEmbeddedAssembies);
165169
helper.AssertContainsEntry ($"assemblies/es/{proj.ProjectName}.resources.dll", shouldContainEntry: expectEmbeddedAssembies);
170+
helper.AssertContainsEntry ($"assemblies/de-DE/{proj.ProjectName}.resources.dll", shouldContainEntry: expectEmbeddedAssembies);
166171
foreach (var abi in rids.Select (AndroidRidAbiHelper.RuntimeIdentifierToAbi)) {
167172
helper.AssertContainsEntry ($"lib/{abi}/libmonodroid.so");
168173
helper.AssertContainsEntry ($"lib/{abi}/libmonosgen-2.0.so");

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ public int GetNumberOfAssemblies (bool forceRefresh = false, AndroidTargetArch a
389389
// Android doesn't allow us to put satellite assemblies in lib/{CULTURE}/assembly.dll.so, we must instead
390390
// mangle the name.
391391
fileTypeMarker = MonoAndroidHelper.MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER;
392-
fileName = $"{culture}-{fileName}";
392+
fileName = $"{culture}{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}{fileName}";
393393
}
394394

395395
var ret = new List<string> ();

src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.Basic.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ public static string MakeZipArchivePath (string part1, ICollection<string>? path
199199
public const string MANGLED_ASSEMBLY_NAME_EXT = ".so";
200200
public const string MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER = "lib_";
201201
public const string MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER = "lib-";
202+
public const string SATELLITE_CULTURE_END_MARKER_CHAR = "_";
202203

203204
/// <summary>
204205
/// Mangles APK/AAB entry name for assembly and their associated pdb and config entries in the
@@ -208,7 +209,7 @@ public static string MakeZipArchivePath (string part1, ICollection<string>? path
208209
public static string MakeDiscreteAssembliesEntryName (string name, string? culture = null)
209210
{
210211
if (!String.IsNullOrEmpty (culture)) {
211-
return $"{MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER}{culture}-{name}{MANGLED_ASSEMBLY_NAME_EXT}";
212+
return $"{MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER}{culture}_{name}{MANGLED_ASSEMBLY_NAME_EXT}";
212213
}
213214

214215
return $"{MANGLED_ASSEMBLY_REGULAR_ASSEMBLY_MARKER}{name}{MANGLED_ASSEMBLY_NAME_EXT}";

src/native/monodroid/embedded-assemblies.hh

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ namespace xamarin::android::internal {
405405
if constexpr (IsSatelliteAssembly) {
406406
// Make sure assembly name is {CULTURE}/assembly.dll
407407
for (size_t idx = start_idx; idx < name.length (); idx++) {
408-
if (name[idx] == SharedConstants::SATELLITE_ASSEMBLY_MARKER_CHAR) {
408+
if (name[idx] == SharedConstants::SATELLITE_CULTURE_END_MARKER_CHAR) {
409409
name[idx] = '/';
410410
break;
411411
}

src/native/runtime-base/shared-constants.hh

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace xamarin::android::internal
2727
static constexpr std::string_view MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER { "lib-" };
2828
static constexpr size_t SATELLITE_ASSEMBLY_MARKER_INDEX = 3; // this ☝️
2929
static constexpr char SATELLITE_ASSEMBLY_MARKER_CHAR = MANGLED_ASSEMBLY_SATELLITE_ASSEMBLY_MARKER[SATELLITE_ASSEMBLY_MARKER_INDEX];
30+
static constexpr char SATELLITE_CULTURE_END_MARKER_CHAR = '_';
3031

3132
static constexpr std::string_view MONO_ANDROID_RUNTIME_ASSEMBLY_NAME { "Mono.Android.Runtime" };
3233
static constexpr std::string_view MONO_ANDROID_ASSEMBLY_NAME { "Mono.Android" };

tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,13 @@ public void BaseZip ()
166166
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Java.Interop.dll.so");
167167
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Mono.Android.dll.so");
168168
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Localization.dll.so");
169-
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib-es-Localization.resources.dll.so");
169+
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib-es{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}Localization.resources.dll.so");
170170
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_UnnamedProject.dll.so");
171171
} else {
172172
expectedFiles.Add ($"lib/{abi}/lib_Java.Interop.dll.so");
173173
expectedFiles.Add ($"lib/{abi}/lib_Mono.Android.dll.so");
174174
expectedFiles.Add ($"lib/{abi}/lib_Localization.dll.so");
175-
expectedFiles.Add ($"lib/{abi}/lib-es-Localization.resources.dll.so");
175+
expectedFiles.Add ($"lib/{abi}/lib-es{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}Localization.resources.dll.so");
176176
expectedFiles.Add ($"lib/{abi}/lib_UnnamedProject.dll.so");
177177
}
178178

@@ -226,13 +226,13 @@ public void AppBundle ()
226226
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Java.Interop.dll.so");
227227
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Mono.Android.dll.so");
228228
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_Localization.dll.so");
229-
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib-es-Localization.resources.dll.so");
229+
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib-es{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}Localization.resources.dll.so");
230230
expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_UnnamedProject.dll.so");
231231
} else {
232232
expectedFiles.Add ($"base/lib/{abi}/lib_Java.Interop.dll.so");
233233
expectedFiles.Add ($"base/lib/{abi}/lib_Mono.Android.dll.so");
234234
expectedFiles.Add ($"base/lib/{abi}/lib_Localization.dll.so");
235-
expectedFiles.Add ($"base/lib/{abi}/lib-es-Localization.resources.dll.so");
235+
expectedFiles.Add ($"base/lib/{abi}/lib-es{MonoAndroidHelper.SATELLITE_CULTURE_END_MARKER_CHAR}Localization.resources.dll.so");
236236
expectedFiles.Add ($"base/lib/{abi}/lib_UnnamedProject.dll.so");
237237
}
238238

0 commit comments

Comments
 (0)