Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make APK and shared library alignment configurable #9046

Merged
merged 2 commits into from
Jun 20, 2024

Conversation

grendello
Copy link
Contributor

Context: https://github.com/dotnet/android/wiki/Android-support-for-devices-with-16k-pages
Context: #9020

Starting sometime next year Google will require all packages submitted
to the Play Store to be aligned to 16 bytes, in order to support Android
devices which use 16kb pages instead of the currently supported 4kb
ones. The requirement also applies to native shared libaries (.so),
which need to be linked so that their loaded sections are aligned to
16kb as well.

This commit implements changes which make the alignment configurable,
while still defaulting to 4kb alignment. The #9020 PR will enable (when
NDK r27 is released) building of our runtime shared libraries with 16kb
alignment. While strictly speaking NDK r27 is not necessary to enable
16kb alignment for the runtime (we could just modify our
CMakeLists.txt script to pass the appropriate flag), I prefer to rely
on the "official" support once NDK r27 is out.

Linking of application shared libraries, however, doesn't use the NDK at
all, and in this case we must pass the appropriate flag to the linker
explicitly.

This commit also prepares our runtime to verify alignment correctly when
changing between 4k and 16k.

Context: https://github.com/dotnet/android/wiki/Android-support-for-devices-with-16k-pages
Context: #9020

Starting sometime next year Google will require all packages submitted
to the Play Store to be aligned to 16 bytes, in order to support Android
devices which use 16kb pages instead of the currently supported 4kb
ones.  The requirement also applies to native shared libaries (`.so`),
which need to be linked so that their loaded sections are aligned to
16kb as well.

This commit implements changes which make the alignment configurable,
while still defaulting to 4kb alignment.  The #9020 PR will enable (when
NDK r27 is released) building of our runtime shared libraries with 16kb
alignment.  While strictly speaking NDK r27 is not necessary to enable
16kb alignment for the runtime (we could just modify our
`CMakeLists.txt` script to pass the appropriate flag), I prefer to rely
on the "official" support once NDK r27 is out.

Linking of application shared libraries, however, doesn't use the NDK at
all, and in this case we must pass the appropriate flag to the linker
explicitly.

This commit also prepares our runtime to verify alignment correctly when
changing between 4k and 16k.
@@ -55,6 +55,9 @@ sealed class ApplicationConfig
public uint jni_remapping_replacement_type_count;
public uint jni_remapping_replacement_method_index_entry_count;

// 3, for 4-byte alignment (4k memory pages); 15, for 16-byte alignment (16k memory pages)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are the mask 3 and 15 respecitvely? noth 4 and 16? (silly question).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With alignment to 4k, bits 0 and 1 of the address must be 0 and with 16k, bits 0-3 must be 0. We could use the actual alignment here and then subtract 1 to obtain a mask from it, but it would require an additional instruction on the run time :) As it is now, we can add 1 to the mask to get the alignment value when reporting an error - an extra instruction but only in error situations, so performance isn't an issue. Yes, I know, it's just one instruction :)

The relevant code is here

uint zipAlignmentMask = ZipAlignmentPages switch {
4 => 3,
16 => 15,
_ => throw new InvalidOperationException ($"Internal error: unsupported zip page alignment value {ZipAlignmentPages}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log an error with an error code instead of throw?

Copy link
Contributor Author

@grendello grendello Jun 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I treat this condition as an internal error, because the property that specifies the alignment is "private" and shouldn't be modified by our users (it's mostly for our convenience of testing) and so I want the invalid value to be signaled in as loud and annoying kind of way :)

uint maxPageSize = ZipAlignmentPages switch {
4 => 4096,
16 => 16384,
_ => throw new InvalidOperationException ($"Internal error: unsupported zip page alignment value {ZipAlignmentPages}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'd use LogError() here too, if we changed the other one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably should just move this switch to a method inside MonoAndroidHelper class.

Comment on lines -329 to +333
case 24: // mono_components_mask: uint32_t / .word | .long
case 24: // zip_alignment_mask: uint32_t / .word | .long
Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}");
ret.zip_alignment_mask = ConvertFieldToUInt32 ("zip_alignment_mask", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]);
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any benefit to putting new settings at the end? Then it could be slightly more compatible with existing files? (Does it even matter?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't matter. There's no guarantee of compatibility between any releases of XA with regards to this (by design).

@grendello grendello merged commit ddb215b into main Jun 20, 2024
58 checks passed
@grendello grendello deleted the dev/grendel/configurable-alignment branch June 20, 2024 19:28
grendello added a commit that referenced this pull request Jun 21, 2024
* main: (26 commits)
  Make APK and shared library alignment configurable (#9046)
  [r8] update proguard rule to keep .NET runtime classes (#9044)
  Explicitly align to 4k (#9041)
  [trimming] preserve custom views and `$(AndroidHttpClientHandlerType)` (#8954)
  Ignore split configs when bundle config moves shared libraries to base.apk (#8987)
  Bump to dotnet/android-tools@1c09dcc (#9026)
  Bump to dotnet/java-interop@ccafbe6 (#9025)
  [Mono.Android-Tests] Fix repo URL in redirect tests (#9035)
  [ci] Update checkout path for nightly build (#9028)
  [ci] Fix android source path for MAUI test job (#9030)
  Link Code of Conduct (#9034)
  [ci] Update sdk-insertions trigger to manual only (#9029)
  Update java-interop and android-tools submodule mentions (#9023)
  LEGO: Merge pull request 9022
  [Xamarin.Android.Build.Tasks] fastdev works with aab files (#8990)
  Use new binutils URL (#9019)
  Localized file check-in by OneLocBuild Task: Build definition ID 17928: Build ID 9686669 (#9011)
  LEGO: Merge pull request 9015
  [api-merge] Update "constant" values to mirror latest API levels (#9004)
  [Mono.Android] Fix wrong value for `ApplicationExitInfoReason.Other` (#9003)
  ...
@github-actions github-actions bot locked and limited conversation to collaborators Jul 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants