Archive 17/01/2023.

Android build problems for stock head

slapin

When I build android APK off stock Urho and install it on my phone via adb, I see
the following error:

03-04 02:09:27.261 26471 26471 E AndroidRuntime: FATAL EXCEPTION: main
03-04 02:09:27.261 26471 26471 E AndroidRuntime: Process: com.github.urho3d, PID: 26471
03-04 02:09:27.261 26471 26471 E AndroidRuntime: java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.github.urho3d/com.github.urho3d.SampleLauncher}: java.lang.ClassNotFoundException: Didn't find class "com.github.urho3d.SampleLauncher" on path: DexPathList[[zip file "/data/app/com.github.urho3d-1/base.apk"],nativeLibraryDirectories=[/data/app/com.github.urho3d-1/lib/arm, /data/app/com.github.urho3d-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2614)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2769)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread.-wrap11(ActivityThread.java)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1591)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:111)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.os.Looper.loop(Looper.java:207)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5933)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:958)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:819)
03-04 02:09:27.261 26471 26471 E AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "com.github.urho3d.SampleLauncher" on path: DexPathList[[zip file "/data/app/com.github.urho3d-1/base.apk"],nativeLibraryDirectories=[/data/app/com.github.urho3d-1/lib/arm, /data/app/com.github.urho3d-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2604)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     ... 9 more
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     Suppressed: java.lang.ClassNotFoundException: com.github.urho3d.SampleLauncher
03-04 02:09:27.261 26471 26471 E AndroidRuntime:         at java.lang.Class.classForName(Native Method)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:         at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:         at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:         at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
03-04 02:09:27.261 26471 26471 E AndroidRuntime:         ... 12 more
03-04 02:09:27.261 26471 26471 E AndroidRuntime:     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

So it looks like something is missing.

I build via cmake then gradle. Where should I look for the problem sosurce?
I never did android development like this before, so please explain it if this is something obvious.

Gradle file:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */
buildscript {
    ext.kotlin_version = '1.1.1'
    repositories {
        // Gradle 4.1 and higher include support for Google's Maven repo using
        // the google() method. And you need to include this repo to download
        // Android plugin 3.0.0 or higher.
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'com.android.application'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.github.urho3d"
        minSdkVersion 11
        targetSdkVersion 14
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
            stl = "stlport_static" // gnustl fails with cstddef not found
        }
    }
    sourceSets.main {
        jniLibs.srcDirs = ["libs"]
        res.srcDirs = ["res"]
        resources.srcDirs = ["src"]
        assets.srcDirs = ["assets"]
        manifest.srcFile "AndroidManifest.xml"
    }
}

APK contents: https://gist.github.com/0365e092881d9e99937a8aa3e65a641a

building:

cd Urho3D
        export PATH=/opt/cmake/bin:${PATH}
        export ANDROID_NDK=/opt/android-ndk/android-ndk-r15c
        export ANDROID_HOME=/opt/android-sdk-linux

        ./cmake_android.sh build-android -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI=armeabi-v7a -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-clang -DANDROID_NATIVE_API_LEVEL=android-14
        cd build-android
        make -j8
        cp ../../dungeon/Android/urho/* .
        /opt/gradle/gradle-4.6/bin/gradle build
        ls -l
        find . -type f -name '*.apk' -ls
        tar zhcf ${WORKSPACE}/build-urho-android.tar.gz bin build/outputs
slapin

I resolved this by using the following build.gradle:

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */
buildscript {
    ext.kotlin_version = '1.1.1'
    repositories {
        // Gradle 4.1 and higher include support for Google's Maven repo using
        // the google() method. And you need to include this repo to download
        // Android plugin 3.0.0 or higher.
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'com.android.application'

task wrapper(type: Wrapper) {
    gradleVersion = '4.6'
}

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.github.urho3d"
        minSdkVersion 11
        targetSdkVersion 14
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
            stl = "stlport_static" // gnustl fails with cstddef not found
        }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    }
    sourceSets.main {
        java.srcDirs = ["src"]
        jniLibs.srcDirs = ["libs"]
        res.srcDirs = ["res"]
        resources.srcDirs = ["src"]
        assets.srcDirs = ["assets"]
        manifest.srcFile "AndroidManifest.xml"
    }
}

but .so jni libraries still miss SDL_main function. Probably it is removed via --gc-sections
linker option. Somehow adding URHO3D_API doesn’t help.

slapin

Ah, it looks that the issue is plain and simple - all objects are build with -fvisibility=hidden.
This prevents functions to be visible in .so. And SDL_main function does not have
any attributes set to unhide it.

slapin

The following patch fixes this problem:

diff --git a/Source/Urho3D/Core/Main.h b/Source/Urho3D/Core/Main.h
index 45968bc..b574f92 100644
--- a/Source/Urho3D/Core/Main.h
+++ b/Source/Urho3D/Core/Main.h
@@ -70,7 +70,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, in
 // Android or iOS or tvOS: use SDL_main
 #elif defined(__ANDROID__) || defined(IOS) || defined(TVOS)
 #define URHO3D_DEFINE_MAIN(function) \
-extern "C" int SDL_main(int argc, char** argv); \
+extern "C" int SDL_main(int argc, char** argv) __attribute__((visibility ("default"))); \^M
 int URHO3D_API SDL_main(int argc, char** argv) \
 { \
     Urho3D::ParseArguments(argc, argv); \