Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/build-and-verify-alignment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: Build and Verify 16KB Page Size Alignment

on:
push:
branches: [ master, main, develop ]
pull_request:
branches: [ master, main, develop ]

jobs:
build-and-verify:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Setup Android SDK
uses: android-actions/setup-android@v3

- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

- name: Verify 16KB Page Size Alignment
run: |
echo "🔍 Checking 16KB page size alignment of 64-bit native libraries..."

# Function to check alignment of a shared library
check_alignment() {
local lib_path="$1"
local lib_name=$(basename "$lib_path")

echo "Checking $lib_name..."

# Use llvm-readelf from NDK to check alignment
local ndk_path="$ANDROID_NDK_ROOT"
local readelf="$ndk_path/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-readelf"

if [ ! -f "$readelf" ]; then
echo "❌ Error: llvm-readelf not found at $readelf"
return 1
fi

# Check LOAD segments alignment
local alignments=$($readelf -l "$lib_path" | grep "LOAD" | awk '{print $NF}')

local all_aligned=true
for alignment in $alignments; do
# Convert hex to decimal
local decimal_alignment=$((alignment))
local kb_alignment=$((decimal_alignment / 1024))

echo " Segment alignment: $alignment ($decimal_alignment bytes = ${kb_alignment}KB)"

if [ $decimal_alignment -ne 16384 ]; then
echo " ❌ Not 16KB aligned (expected 0x4000 = 16384 bytes)"
all_aligned=false
else
echo " ✅ 16KB aligned"
fi
done

if [ "$all_aligned" = true ]; then
echo "✅ $lib_name is properly 16KB aligned"
return 0
else
echo "❌ $lib_name has incorrect alignment"
return 1
fi
}

# Find all .so files in build outputs (64-bit architectures only)
echo "Finding 64-bit native libraries in build outputs..."
so_files=$(find . -path "*/build/intermediates/cxx/*/obj/*/*.so" -type f | grep -E "(Release|RelWithDebInfo)" | grep -E "(arm64-v8a|x86_64)" | head -20)

if [ -z "$so_files" ]; then
echo "❌ No native libraries found in build outputs"
exit 1
fi

echo "Found native libraries:"
echo "$so_files"
echo

# Check alignment for each library
all_libs_aligned=true
for so_file in $so_files; do
if ! check_alignment "$so_file"; then
all_libs_aligned=false
fi
echo
done

# Summary
echo "📊 Alignment Verification Summary:"
if [ "$all_libs_aligned" = true ]; then
echo "🎉 All native libraries are properly 16KB aligned!"
echo "✅ This build is compatible with 16KB page size devices"
else
echo "❌ Some libraries are not properly aligned"
echo "💡 Ensure you're using Android Gradle Plugin 8.5.1+ and target SDK 35+"
exit 1
fi

- name: Verify AAR Contents
run: |
echo "🔍 Verifying AAR files contain native libraries..."

# Find AAR files
aar_files=$(find . -name "*.aar" -path "*/build/outputs/aar/*" -type f)

if [ -z "$aar_files" ]; then
echo "❌ No AAR files found"
exit 1
fi
Comment on lines +130 to +135
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Reconsider the failure condition for missing AAR files.

The workflow exits with error if no AAR files are found (line 134). This will cause CI failures for Android app projects that don't produce AARs (libraries produce AARs, but apps produce APKs). The AAR verification step should be optional or conditional.

Example fix:

         if [ -z "$aar_files" ]; then
-          echo "❌ No AAR files found"
-          exit 1
+          echo "ℹ️  No AAR files found (this may be an app project rather than a library)"
+          exit 0
         fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
aar_files=$(find . -name "*.aar" -path "*/build/outputs/aar/*" -type f)
if [ -z "$aar_files" ]; then
echo "No AAR files found"
exit 1
fi
aar_files=$(find . -name "*.aar" -path "*/build/outputs/aar/*" -type f)
if [ -z "$aar_files" ]; then
echo "ℹ️ No AAR files found (this may be an app project rather than a library)"
exit 0
fi


echo "Found AAR files:"
for aar in $aar_files; do
echo "📦 $(basename $aar)"

# Check if AAR contains native libraries
native_libs=$(unzip -l "$aar" | grep -E "jni/.*\.so$" | wc -l)

if [ $native_libs -gt 0 ]; then
echo " ✅ Contains $native_libs native libraries"
echo " 📋 Native library details:"
unzip -l "$aar" | grep -E "jni/.*\.so$" | awk '{print " " $4}'
else
echo " ℹ️ No native libraries (library may be pure Java/Kotlin)"
fi
echo
done

- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: build-outputs
path: |
**/build/outputs/aar/*.aar
**/build/intermediates/cxx/*/obj/*/*.so
retention-days: 7

- name: Upload lint reports
uses: actions/upload-artifact@v4
if: always()
with:
name: lint-reports
path: |
**/build/reports/lint-results-*.html
retention-days: 7
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
/captures
/local.properties
.externalNativeBuild
.cxx
.cxx
.java-version
8 changes: 2 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.5.20'
ext.kotlin_version = '2.1.20'
repositories {
mavenLocal()
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath 'com.android.tools.build:gradle:8.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

//classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

Expand Down
108 changes: 74 additions & 34 deletions dashj-bls/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ plugins {
id 'signing'
id 'kotlin-android'
id 'kotlin-kapt'
id 'org.jreleaser' version '1.17.0'
}
version "1.0.1-SNAPSHOT"
android {
compileSdkVersion 31
namespace "org.dashj.bls"
compileSdkVersion 34

defaultConfig {
minSdkVersion 23
targetSdkVersion 31
targetSdkVersion 35
versionCode 1
versionName "1.0.0"
versionName "$version"

defaultConfig {
ndk {
Expand All @@ -36,33 +39,32 @@ android {
main.java.srcDirs += 'src/main/java'
}

kotlinOptions { jvmTarget = '1.8' }
kotlinOptions { jvmTarget = '17' }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
version '3.18.1'
version '3.22.1'
}
}
ndkVersion '23.2.8568313'
ndkVersion '29.0.14206865'

publishing {
singleVariant("release") {
// if you don't want sources/javadoc, remove these lines
withSourcesJar()
//withSourcesJar()
//withJavadocJar()
}
}
}

version '1.0.0'

dependencies {
api 'org.dashj:dashj-bls:1.0.0'
api 'org.dashj:dashj-bls:1.0.1'
testImplementation 'junit:junit:4.13.2'
}

repositories {
Expand All @@ -71,18 +73,21 @@ repositories {
}

task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
source = fileTree(dir: 'src/main/java', include: '**/*.java')
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
exclude '**/BuildConfig.java'
exclude '**/R.java'
failOnError false
}

task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
task javadocJar(type: Jar) {
archiveClassifier = 'javadoc'
// Create empty javadoc jar for now
}

task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
archiveClassifier = 'sources'
}

artifacts {
Expand All @@ -101,21 +106,21 @@ task comps {
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
groupId group
artifactId 'dashj-bls-android'
mavenJava(MavenPublication) {
artifactId = 'dashj-bls-android'
version "$version"
from components.release

artifact sourcesJar
artifact javadocJar
pom {
name = 'DashJ-BLS-Android'
description = 'Dash BLS Android Library'
url = 'httsp://dashj.org'
url = 'https://github.com/dashpay/dashj-android'

licenses {
license {
name = 'MIT'
url = 'https://opensource.org/licenses/MIT'
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
Expand All @@ -135,20 +140,55 @@ afterEvaluate {
}
repositories {
maven {
// change URLs to point to your repos, e.g. http://my.org/repo
def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = project.hasProperty('ossrhUsername') ? project.findProperty('ossrhUsername') : ''
password = project.hasProperty('ossrhPassword') ? project.findProperty('ossrhPassword') : ''
}
url = layout.buildDirectory.dir('staging-deploy')
}
}
}

signing {
required { gradle.taskGraph.hasTask("publish") }
println("Components: " + publishing.publications)
sign publishing.publications.release
sign publishing.publications.mavenJava
}
}

jreleaser {
def projectVersion = version
project {
name = 'dashj-bls-android'
description = 'Dash BLS Android Library'
website = 'https://github.com/dashpay/dashj-android'
authors = ['HashEngineering']
license = 'The Apache License, Version 2.0'
gitRootSearch = true
version = projectVersion
}

signing {
active = 'ALWAYS'
armored = true
}

deploy {
maven {
mavenCentral {
sonatype {
active = 'ALWAYS'
url = 'https://central.sonatype.com/api/v1/publisher'
stagingRepository("$buildDir/staging-deploy")
}
}
nexus2 {
app {
active = 'SNAPSHOT'
url = 'https://central.sonatype.com/repository/maven-snapshots/'
snapshotUrl = 'https://central.sonatype.com/repository/maven-snapshots/'
applyMavenCentralRules = true
snapshotSupported = true
closeRepository = true
releaseRepository = true
stagingRepository("$buildDir/staging-deploy")
}
}
}
}
}
Loading