Just made my android app in Rust. It crashes

Hi! I've built my android APK with cargo apk, but when I run it - it crahes. What did I do wrong?

Something.

If you want useful help, you'll have to provide useful information about the kind of error you got.

4 Likes

Did you compile for the correct cpu architecture? Does it crash with a specific error?

Sorry. My main.rs is

#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
fn main() {
    enumerate_audio_devices().unwrap();
}

const GET_DEVICES_OUTPUTS: jni::sys::jint = 2;

fn enumerate_audio_devices() -> Result<(), Box<dyn std::error::Error>> {
    // Create a VM for executing Java calls
    let native_activity = ndk_glue::native_activity();
    let vm_ptr = native_activity.vm();
    let vm = unsafe { jni::JavaVM::from_raw(vm_ptr) }?;
    let env = vm.attach_current_thread()?;

    // Query the global Audio Service
    let class_ctxt = env.find_class("android/content/Context")?;
    let audio_service = env.get_static_field(class_ctxt, "AUDIO_SERVICE", "Ljava/lang/String;")?;

    let audio_manager = env
        .call_method(
            native_activity.activity(),
            "getSystemService",
            // JNI type signature needs to be derived from the Java API
            // (ArgTys)ResultTy
            "(Ljava/lang/String;)Ljava/lang/Object;",
            &[audio_service],
        )?
        .l()?;

    // Enumerate output devices
    let devices = env.call_method(
        audio_manager,
        "getDevices",
        "(I)[Landroid/media/AudioDeviceInfo;",
        &[GET_DEVICES_OUTPUTS.into()],
    )?;

    println!("-- Output Audio Devices --");

    let device_array = devices.l()?.into_inner();
    let len = env.get_array_length(device_array)?;
    for i in 0..len {
        let device = env.get_object_array_element(device_array, i)?;

        // Collect device information
        // See https://developer.android.com/reference/android/media/AudioDeviceInfo
        let product_name: String = {
            let name =
                env.call_method(device, "getProductName", "()Ljava/lang/CharSequence;", &[])?;
            let name = env.call_method(name.l()?, "toString", "()Ljava/lang/String;", &[])?;
            env.get_string(name.l()?.into())?.into()
        };
        let id = env.call_method(device, "getId", "()I", &[])?.i()?;
        let ty = env.call_method(device, "getType", "()I", &[])?.i()?;

        let sample_rates = {
            let sample_array = env
                .call_method(device, "getSampleRates", "()[I", &[])?
                .l()?
                .into_inner();
            let len = env.get_array_length(sample_array)?;

            let mut sample_rates = vec![0; len as usize];
            env.get_int_array_region(sample_array, 0, &mut sample_rates)?;
            sample_rates
        };

        println!("Device {}: Id {}, Type {}", product_name, id, ty);
        println!("sample rates: {:#?}", sample_rates);
    }

    Ok(())
}

cargo.toml:

[package]
name = "android_test"
version = "0.1.0"
authors = ["..."]
edition = "2018"
crate-type = ["lib", "cdylib"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[target.'cfg(target_os = "android")'.dependencies]
ndk-glue = { version="*" }
ndk = { version = "*", features = ["trace"] }
jni = "0.17"

[package.metadata.android]
apk_label = "Rust apk test"
target_sdk_version = 29
min_sdk_version = 26

I've built it with cargo apk

PS C:\Users\...\project\android_test> cargo apk build --release
Warning: You use environment variable ANDROID_HOME that is deprecated.Please, remove it and use ANDROID_SDK_ROOT instead. Now ANDROID_HOME is used
warning: unused manifest key: package.crate-type
    Finished release [optimized] target(s) in 3.06s
Error: Path "C:\\Users\\...\\project\\android_test\\target\\aarch64-linux-android\\release\\libandroid_test.so" doesn't exist.
PS C:\Users\...\project\android_test> 

crash

If you have the Android development tools installed, the adb logcat command should show you more information about the crash.

logcat

Relevant log:

09-25 22:39:51.585 16911 16911 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{rust.android_test/android.app.NativeActivity}: java.lang.IllegalArgumentException: Unable to find native library android_test using classloader: dalvik.system.PathClassLoader[DexPathList[[],nativeLibraryDirectories=[/data/app/rust.android_test-hiDUFecEbpAG8I_acWqtwA==/lib/arm64, /system/lib64]]]
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3363)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3498)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2255)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:193)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:7169)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
09-25 22:39:51.585 16911 16911 E AndroidRuntime: Caused by: java.lang.IllegalArgumentException: Unable to find native library android_test using classloader: dalvik.system.PathClassLoader[DexPathList[[],nativeLibraryDirectories=[/data/app/rust.android_test-hiDUFecEbpAG8I_acWqtwA==/lib/arm64, /system/lib64]]]
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.NativeActivity.onCreate(NativeActivity.java:161)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:7193)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.Activity.performCreate(Activity.java:7184)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3343)
09-25 22:39:51.585 16911 16911 E AndroidRuntime:        ... 11 more
09-25 22:39:51.589  1984 10335 W ActivityManager:   Force finishing activity rust.android_test/android.app.NativeActivity
[package]
name = "android_test"
version = "0.1.0"
authors = ["..."]
edition = "2018"
crate-type = ["lib", "cdylib"]
warning: unused manifest key: package.crate-type

The crate-type must be in a [lib] section. Also main.rs should be called lib.rs I think.

5 Likes

Thank you! It works!

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.