Skip to content
New issue

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

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

Already on GitHub? # to your account

android: Update Gradle, Android plugin, build tools, NDK #942

Merged
merged 15 commits into from
Sep 2, 2022

Conversation

ilammy
Copy link
Collaborator

@ilammy ilammy commented Aug 30, 2022

These weekly emails about Android build tick me off. Of course Google has to keep breaking stuff, because how else we can progress as a species if Googlers aren't getting promotions for improving something in Android ecosystem. Anyway... you can read some rants in commit messages if you like.

Changes for users of AndroidThemis

None. If you simply get binaries from Maven, those will work. No action required.

We still support minimum Android API 21.

...but if you're building AndroidThemis from source

Then you're in for an update:

  • Gradle: 5.6.4 => 7.3.3
  • Android Gradle plugin: 3.2.1 => 7.2.2
  • Android build tools: 28.0.3 => 30.0.3
  • Android SDK: 28 => 30
  • Android NDK: ??? => 25.0.8775105

Gradle wrapper will download everything automatically. If you open the project in Android Studio, it should build right away.

But why?

Because existing build does not build with modern Android SDKs. Our CI does not built it either.

AndroidThemis has to target at least SDK 30 to be allowed into Play store. People will start nagging us about that. I've upgraded to the latest stuff I can test against. SDK 30 is not the latest SDK, but that's what my phone supports 😞

Other changes

In addition to all this, update the way BoringSSL is built. Newer NDK changes the way native binaries are compiled and reused. Instead of fighting gravity and innovation, I've replaced the old ndk-build with CMake scripts, integrating BoringSSL build into libthemis_jni.so build directly. Hopefully, that's all we need for the forseeable future. Until Google decides to deprecate CMake for Android.

Checklist

  • Change is covered by automated tests
  • The coding guidelines are followed
  • Example projects and code samples are up-to-date (nope, maybe when we make a new release?)
  • Changelog is updated

ilammy added 9 commits August 30, 2022 21:51
Bumping Android Gradle plugin to 7.2.2 so that it picks up new SDKs
and bumping Gradle to 7.3.3 so that it works with the new plugin,
and Android build tools to 30.0.3 so that Gradle works, and with
those new tools NDK has to be configured differently (finally,
it can be pinned in the project configuration itself, instead of
being a free variable in the build machine configuration).

This is quite a YOLO upgrade over multiple major versions, but I don't
think we have a choice. The treadmill must roll forward, because how
else we can Innovate™ to keep the number going up. Otherwise, I can't
build Android Themis anymore with today's tooling.
Because Android Studio is being annoying about it, *strongly* suggesting
you target the minimum allowed SDK on Google Play. Coincidentally, this
is also the version of the SDK that my phone uses, so I let it pass.

Note that *minimum* SDK level is still set at 21, we should still be
able to run on older devices. Hopefully someone tests that, lol.
New Android stuff is finally available in Google repos and we don't
need JCenter anymore. Good night, sweet prince.
Because why not, I'm on a roll. Clicking clickety things in the IDE.
These are only used in tests.

Unfortunately, Kotlin cannot be updated past 1.4.x branch (current
one is 1.7.x) because it desugars into some too new Java 1.8 stuff
which is not supported on Android API 21. We'd have to bump our
minimum API level to use newer versions. So not today.
Android has its own annotations under "android" and they conflict
with Jetbrains annotations. I was never motivated enough to unify
them so instead we've been filtering them out for Android builds.

New Gradle -- new approach. Such innovative. Much simpler.
Here's a thing. New SDK and NDK build native code differently because of
course they do. For example, no more .externalNativeBuild directory
with a single build, instead there is .cxx directory with separate
debug and release builds under pseudorandom subdirectory.

Good news is that Google has finally implemented a way to share native
libraries via AARs. Right now we're building BoringSSL as a separate
project and it technically produced an AAR before. But it could not
be reused by other AARs, we directed the build to look at headers
in our source tree and picked up binaries from the build tree.

The new way -- Prefab -- adds a whole bunch of complexity that abstracts
out native library building process, introduces a bunch of structure
into how native libraries are distributed, ultimately allowing to pack
your native libraries into reusable AAR artifacts.

Bad news is that this is Google project, so obviously it was implemented
by someone aiming for a promotion, adds a whole bunch of complexity to
solve 80% of the problem -- except that *our* project is in that 20%
which does not fucking work out of the fucking box and there is not way
to fix it because of all abstraction.

Main problem here is that BoringSSL uses CMake build system while
libthemis_jni is still built using ndk-build, and that combo is not
very well-supported withing the same project. There are reports that
Prefab actually works in the consumer project is build using CMake.

However.

If I were to implemement CMake build for libthemis_jni, then I can
simply add_subdirectory() with BoringSSL and build it right there.

As long as we don't actually planning to distribute our builds of
BoringSSL separately -- and we probably don't, judging how well that
worked out for OpenSSL on iOS -- as long as we don't need AARs,
we don't really need Prefab.

So that's what I'm gonna do. Write a CMake build script for
libthemis_jni and use it for all native code of Android Themis.
Now that the script is there, replace ndk-build with CMake.

While we're here, pin the verison of CMake in build.gradle
so that it's more reproducible.
I don't think we'd ever want to go back to ndk-build, drop it.
Since now BoringSSL is a part of ":android" native code, there is no
need to build it as a separate project. We don't have other users.
@ilammy ilammy added O-Android 🤖 Operating system: Android infrastructure Automated building and packaging labels Aug 30, 2022
@ilammy ilammy requested review from vixentael, shadinua and a team August 30, 2022 13:05
// on this Gradle version until it breaks or we *need* an upgrade:
classpath 'com.android.tools.build:gradle:3.2.1'
// Android Gradle plugin
classpath 'com.android.tools.build:gradle:7.2.2'
Copy link
Contributor

Choose a reason for hiding this comment

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

+4 versions! bold.

Copy link
Contributor

@vixentael vixentael left a comment

Choose a reason for hiding this comment

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

you are so brave to dig into android ecosystem

Comment on lines -71 to -77
tasks.whenTaskAdded { task ->
def excludeBoringSSL = [
'publish',
'publishToMavenLocal',
'publishProductionPublicationToMavenRepository',
'publishProductionPublicationToMavenLocal',
'generatePomFileForProductionPublication',
Copy link
Contributor

Choose a reason for hiding this comment

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

will this change the way we publish Android Themis?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

will this change the way we publish Android Themis?

No. Same tasks for :android should be used and should work.

I didn't test tho. Later, since this needs to be tested against that golden Docker image, which is probably royally rotten by now and will need to be updated as well to work with all this new SDK stuff.

This removed block was in fact a hack setting up dependencies between :android and :boringssl projects, so that BoringSSL binaries are build before Android JNI code is build. That broke down with new NDK since the task names for building CMake and ndk-build are now different. However, with the build unified into CMake, this hack become unnecessary in principle – thus off it goes.

ilammy added 5 commits August 30, 2022 22:53
Harmonize NDK version with what's preinstalled in GitHub Actions
environments, shaving off some minutes from build time. We don't
particularly care about the NDK version, as long as it's some
modern version that might be supported for some next years.
It has newer Android build tools. And yes, still macOS, because running
Android emulator on Linux still sucks on GitHub Actions.
No longer necessary. Newer Android tooling is able to filter that out,
and it's not installed in newer environments anyway.
But Java 8 for Android's sdkmanager. IKR
Just in case CI environment changes. They typically don't change
defaults and keep stuff installed, but who knows. Be explicit.
@ilammy
Copy link
Collaborator Author

ilammy commented Aug 30, 2022

Woops, I saw 25 in virtual environment descriptions, but I did not notice that it's for macos-11 environment and the version is different. Rolled back NDK version a notch, updated CI scripts. Now they should be using whatever GitHub has in their environment, shaving off some 2-3 minutes from build time, otherwise wasted downloading stuff.

@ilammy
Copy link
Collaborator Author

ilammy commented Aug 30, 2022

omigod, omigod!

> Task :android:connectedDebugAndroidTest
Starting 139 tests on test(AVD) - 10

Test results saved as file:/Users/runner/work/themis/themis/src/wrappers/themis/android/build/outputs/androidTest-results/connected/test-result.pb. Inspect these results in Android Studio by selecting Run > Import Tests From File from the menu bar and importing test-result.pb.

> Task :android:connectedAndroidTest

BUILD SUCCESSFUL in 2m 36s
54 actionable tasks: 40 executed, 14 up-to-date

Is this what happiness looks like?

@radetsky
Copy link
Contributor

Thank you very much!

@vixentael vixentael self-requested a review August 30, 2022 20:19
@vixentael
Copy link
Contributor

@shadinua do you have time to take a look, or shall we merge?

New SDK calls it "android-release.aar", not just "android.aar".
@ilammy
Copy link
Collaborator Author

ilammy commented Aug 31, 2022

Alrighty. I've checked the release publishing. Docker image indeed required some updates (cossacklabs/dockerfiles#6). After that I was able to build AAR in that image, sign it with a random key, and upload it to Sonatype staging repo. Of course, can't get past since I don't have the real signing key. But the pipeline should be still working.

@vixentael
Copy link
Contributor

@vixentael vixentael merged commit 5897031 into cossacklabs:master Sep 2, 2022
@ilammy ilammy deleted the android-madness branch September 2, 2022 10:16
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
infrastructure Automated building and packaging O-Android 🤖 Operating system: Android
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants