Skip to content

Commit

Permalink
Merge branch 'implement-gradle-rust-plugin-droid-1377'
Browse files Browse the repository at this point in the history
  • Loading branch information
Pururun committed Jan 8, 2025
2 parents ac9ac4b + a07dc5c commit a4bd7cc
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 160 deletions.
85 changes: 45 additions & 40 deletions .github/workflows/android-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
retention-days: 7

generate-relay-list:
name: Generate relay list
name: Generate relay list # Used by wait for jobs.
needs: prepare
runs-on: ubuntu-latest
container:
Expand Down Expand Up @@ -129,11 +129,8 @@ jobs:

- name: Generate
if: steps.cache-relay-list.outputs.cache-hit != 'true'
env:
RUSTFLAGS: --deny warnings
run: |
mkdir -p android/app/build/extraAssets
cargo run --bin relay_list > android/app/build/extraAssets/relays.json
shell: bash
run: ./android/gradlew -p android generateRelayList

- name: Upload
uses: actions/upload-artifact@v4
Expand All @@ -144,26 +141,22 @@ jobs:
retention-days: 7

build-native:
name: Build native
name: Build native # Used by wait for jobs.
needs: prepare
runs-on: ubuntu-latest
container:
image: "${{ needs.prepare.outputs.container_image }}"
strategy:
matrix:
include:
- arch: "x86_64"
abi: "x86_64"
target: "x86_64-linux-android"
- arch: "i686"
abi: "x86"
target: "i686-linux-android"
- arch: "aarch64"
abi: "arm64-v8a"
target: "aarch64-linux-android"
- arch: "armv7"
abi: "armeabi-v7a"
target: "armv7-linux-androideabi"
- abi: "x86_64"
task-variant: "X86_64"
- abi: "x86"
task-variant: "X86"
- abi: "arm64-v8a"
task-variant: "Arm64"
- abi: "armeabi-v7a"
task-variant: "Arm"
steps:
# Fix for HOME path overridden by GH runners when building in containers, see:
# https://github.com/actions/runner/issues/863
Expand Down Expand Up @@ -197,27 +190,28 @@ jobs:
env:
cache_hash: ${{ steps.native-lib-cache-hash.outputs.native_lib_hash }}
with:
path: ./android/app/build/extraJni
path: ./android/app/build/rustJniLibs/android
key: android-native-libs-${{ runner.os }}-${{ matrix.abi }}-${{ env.cache_hash }}

- name: Build native libraries
if: steps.cache-native-libs.outputs.cache-hit != 'true'
env:
RUSTFLAGS: --deny warnings
BUILD_TYPE: debug
run: |
ARCHITECTURES="${{ matrix.abi }}"
UNSTRIPPED_LIB_PATH="$CARGO_TARGET_DIR/${{ matrix.target }}/$BUILD_TYPE/libmullvad_jni.so"
STRIPPED_LIB_PATH="./android/app/build/extraJni/${{ matrix.abi }}/libmullvad_jni.so"
NDK_TOOLCHAIN_STRIP_TOOL="$NDK_TOOLCHAIN_DIR/llvm-strip"
cargo build --target ${{ matrix.target }} --verbose --package mullvad-jni --features api-override
$NDK_TOOLCHAIN_STRIP_TOOL --strip-debug --strip-unneeded -o "$STRIPPED_LIB_PATH" "$UNSTRIPPED_LIB_PATH"
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
arguments: cargoBuild${{ matrix.task-variant }}
gradle-version: wrapper
build-root-directory: android
execution-only-caches: false
# Disable if logs are hard to follow.
concurrent: true
read-only: ${{ github.ref != 'refs/heads/main' }}


- name: Upload native libs
uses: actions/upload-artifact@v4
with:
name: native-libs-${{ matrix.arch }}
path: android/app/build/extraJni
name: native-libs-${{ matrix.abi }}
path: android/app/build/rustJniLibs/android
if-no-files-found: error
retention-days: 7

Expand Down Expand Up @@ -290,7 +284,9 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
arguments: compileOssProdDebugKotlin
arguments: |
compileOssProdDebugKotlin
-x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: false
Expand All @@ -299,24 +295,26 @@ jobs:
read-only: ${{ github.ref != 'refs/heads/main' }}

- name: Wait for other jobs (native, relay list)
uses: kachick/wait-other-jobs@v2.0.3
uses: kachick/wait-other-jobs@v3.6.0
with:
wait-seconds-before-first-polling: '0'
wait-list: |
[
{
"workflowFile": "android-app.yml",
"jobName": "build-native"
"jobMatchMode": "prefix",
"jobName": "Build native"
},
{
"workflowFile": "android-app.yml",
"jobName": "generate-relay-list"
"jobName": "Generate relay list"
}
]
- uses: actions/download-artifact@v4
with:
pattern: native-libs-*
path: android/app/build/extraJni
path: android/app/build/rustJniLibs/android
merge-multiple: true

- uses: actions/download-artifact@v4
Expand All @@ -328,7 +326,9 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
arguments: assembleOssProdDebug
arguments: |
assembleOssProdDebug
-x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: true
Expand All @@ -341,7 +341,9 @@ jobs:
if: github.event.inputs.run_firebase_tests == 'true'
with:
job-id: jdk17
arguments: assemblePlayStagemoleDebug
arguments: |
assemblePlayStagemoleDebug
-x cargoBuild
gradle-version: wrapper
build-root-directory: android
execution-only-caches: true
Expand Down Expand Up @@ -396,7 +398,10 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
arguments: ${{ matrix.assemble-command }}
arguments: |
${{ matrix.assemble-command }}
-x cargoBuild
-x generateRelayList
gradle-version: wrapper
build-root-directory: android
execution-only-caches: false
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/daemon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ on:
- '!.github/CODEOWNERS'
- '!android/**'
- '!audits/**'
- '!build-apk.sh'
- '!build.sh'
- '!ci/**'
- 'ci/check-rust.sh'
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/testframework.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ on:
- '.github/workflows/daemon.yml'
- '!android/**'
- '!audits/**'
- '!build-apk.sh'
- '!build.sh'
- '!ci/**'
- '!clippy.toml'
Expand Down
10 changes: 5 additions & 5 deletions android/BuildInstructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ Linux distro:

```bash
cd "$ANDROID_HOME" # Or some other directory to place the Android NDK
wget https://dl.google.com/android/repository/android-ndk-r27b-linux.zip
unzip android-ndk-r27b-linux.zip
wget https://dl.google.com/android/repository/android-ndk-r27c-linux.zip
unzip android-ndk-r27c-linux.zip

cd android-ndk-r27b
cd android-ndk-r27c
export ANDROID_NDK_HOME="$PWD"
```

Expand Down Expand Up @@ -162,15 +162,15 @@ Run the following command to download wireguard-go-rs submodule: `git submodule
### Debug build
Run the following command to build a debug build:
```bash
../build-apk.sh --dev-build
../android/build.sh --dev-build
```

### Release build
1. Configure a signing key by following [these instructions](#configure-signing-key).
2. Move, copy or symlink the directory from step 1 to [./credentials/](./credentials/) (`<repository>/android/credentials/`).
3. Run the following command to build:
```bash
../build-apk.sh --app-bundle
../android/build.sh --app-bundle
```

## Configure signing key
Expand Down
110 changes: 86 additions & 24 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import com.android.build.gradle.internal.tasks.factory.dependsOn
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
import java.io.ByteArrayOutputStream
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.Properties
import org.gradle.internal.extensions.stdlib.capitalized

Expand All @@ -13,6 +15,7 @@ plugins {
alias(libs.plugins.kotlin.ksp)
alias(libs.plugins.compose)
alias(libs.plugins.protobuf.core)
alias(libs.plugins.rust.android.gradle)

id(Dependencies.junit5AndroidPluginId) version Versions.junit5Plugin
}
Expand All @@ -21,7 +24,6 @@ val repoRootPath = rootProject.projectDir.absoluteFile.parentFile.absolutePath
val extraAssetsDirectory = layout.buildDirectory.dir("extraAssets").get()
val relayListPath = extraAssetsDirectory.file("relays.json").asFile
val defaultChangelogAssetsDirectory = "$repoRootPath/android/src/main/play/release-notes/"
val extraJniDirectory = layout.buildDirectory.dir("extraJni").get()

val credentialsPath = "${rootProject.projectDir}/credentials"
val keystorePropertiesFile = file("$credentialsPath/keystore.properties")
Expand All @@ -35,6 +37,7 @@ android {
namespace = "net.mullvad.mullvadvpn"
compileSdk = Versions.compileSdkVersion
buildToolsVersion = Versions.buildToolsVersion
ndkVersion = Versions.ndkVersion

defaultConfig {
val localProperties = gradleLocalProperties(rootProject.projectDir, providers)
Expand Down Expand Up @@ -126,7 +129,6 @@ android {
.getOrDefault("OVERRIDE_CHANGELOG_DIR", defaultChangelogAssetsDirectory)

assets.srcDirs(extraAssetsDirectory, changelogDir)
jniLibs.srcDirs(extraJniDirectory)
}
}

Expand Down Expand Up @@ -239,12 +241,14 @@ android {

createDistBundle.dependsOn("bundle$capitalizedVariantName")

// Ensure all relevant assemble tasks depend on our ensure tasks.
tasks["assemble$capitalizedVariantName"].apply {
dependsOn(tasks["ensureRelayListExist"])
dependsOn(tasks["ensureJniDirectoryExist"])
dependsOn(tasks["ensureValidVersionCode"])
}
// Ensure we have relay list ready before merging assets.
tasks["merge${capitalizedVariantName}Assets"].dependsOn(tasks["generateRelayList"])

// Ensure that we have all the JNI libs before merging them.
tasks["merge${capitalizedVariantName}JniLibFolders"].dependsOn("cargoBuild")

// Ensure all relevant assemble tasks depend on our ensure task.
tasks["assemble$capitalizedVariantName"].dependsOn(tasks["ensureValidVersionCode"])
}
}

Expand All @@ -255,6 +259,80 @@ junitPlatform {
}
}

cargo {
val isReleaseBuild = isReleaseBuild()
val enableApiOverride = !isReleaseBuild || isAlphaOrDevBuild()
module = repoRootPath
libname = "mullvad-jni"
// All available targets:
// https://github.com/mozilla/rust-android-gradle/tree/master?tab=readme-ov-file#targets
targets =
gradleLocalProperties(rootProject.projectDir, providers)
.getProperty("CARGO_TARGETS")
?.split(",") ?: listOf("arm", "arm64", "x86", "x86_64")
profile =
if (isReleaseBuild) {
"release"
} else {
"debug"
}
prebuiltToolchains = true
targetDirectory = "$repoRootPath/target"
features {
if (enableApiOverride) {
defaultAnd(arrayOf("api-override"))
}
}
targetIncludes = arrayOf("libmullvad_jni.so")
extraCargoBuildArguments = buildList {
add("--package=mullvad-jni")
if (isReleaseBuild) {
add("--locked")
}
}
}

tasks.register<Exec>("generateRelayList") {
workingDir = File(repoRootPath)
standardOutput = ByteArrayOutputStream()

onlyIf { isReleaseBuild() || !relayListPath.exists() }

commandLine("cargo", "run", "--bin", "relay_list")

doLast {
val output = standardOutput as ByteArrayOutputStream
// Create file if needed
relayListPath.parentFile.mkdirs()
relayListPath.createNewFile()
FileOutputStream(relayListPath).use { it.write(output.toByteArray()) }
}
}

tasks.register<Exec>("cargoClean") {
workingDir = File(repoRootPath)
commandLine("cargo", "clean")
}

if (
gradleLocalProperties(rootProject.projectDir, providers)
.getProperty("CLEAN_CARGO_BUILD")
?.toBoolean() != false
) {
tasks["clean"].dependsOn("cargoClean")
}

// This is a hack and will not work correctly under all scenarios.
// See DROID-1696 for how we can improve this.
fun isReleaseBuild() =
gradle.startParameter.getTaskNames().any { it.contains("release", ignoreCase = true) }

fun isAlphaOrDevBuild(): Boolean {
val localProperties = gradleLocalProperties(rootProject.projectDir, providers)
val versionName = generateVersionName(localProperties)
return versionName.contains("dev") || versionName.contains("alpha")
}

androidComponents {
beforeVariants { variantBuilder ->
variantBuilder.enable =
Expand All @@ -276,22 +354,6 @@ configure<org.owasp.dependencycheck.gradle.extension.DependencyCheckExtension> {
skipConfigurations = listOf("lintClassPath")
}

tasks.register("ensureRelayListExist") {
doLast {
if (!relayListPath.exists()) {
throw GradleException("Missing relay list: $relayListPath")
}
}
}

tasks.register("ensureJniDirectoryExist") {
doLast {
if (!extraJniDirectory.asFile.exists()) {
throw GradleException("Missing JNI directory: $extraJniDirectory")
}
}
}

// This is a safety net to avoid generating too big version codes, since that could potentially be
// hard and inconvenient to recover from.
tasks.register("ensureValidVersionCode") {
Expand Down
Loading

0 comments on commit a4bd7cc

Please sign in to comment.