Android 应用程序在加载库时崩溃,找不到入口点 getThreadLocalsEv,如何修复? [已添加示例]

问题描述 投票:0回答:1

我的代码在

System.loadLibrary("hypoboleus");
上崩溃,并出现找不到入口点的错误。我创建了一个
so
文件并将其作为
app/src/main/jniLibs/arm64-v8a/
包含在
libhypoboleus.so
文件夹中。 Java 运行时正在调用
java.lang.Runtime.loadLibrary0
,它试图从我的
getThreadLocalsEv
文件运行
so
编辑:在本问题末尾添加示例代码。

这曾经在 NDK 的早期版本中工作,但我升级了,然后它让我更改了我的构建脚本。我当前的 NDK 版本是

25.2.9519653

具体消息文字为

java.lang.UnsatisfiedLinkError: dlopen failed: TLS symbol "_ZZN8gwp_asan15getThreadLocalsEvE6Locals" in dlopened "/data/app/~~nqWwoXRjQhq9nhyacG54hA==/hk.jennyemily.hypoboleus-EFD9ul4kulUwExi3Ee0LJQ==/base.apk!/lib/arm64-v8a/libhypoboleus.so" referenced from "/data/app/~~nqWwoXRjQhq9nhyacG54hA==/hk.jennyemily.hypoboleus-EFD9ul4kulUwExi3Ee0LJQ==/base.apk!/lib/arm64-v8a/libhypoboleus.so" using IE access model

入口点存在于

so
文件中:
nm -D
给出
0000000000000000 W _ZZN8gwp_asan15getThreadLocalsEvE6Locals

我的构建线是 path-to-ndk

/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -target aarch64-linux-android-clang -nostartfiles -shared
path
/hypoboleus_wrap.c 
path
/libhypoboleus_c.a -lm -lz -o 
path
/libhypoboleus.so -I 
path
 -fPIC
[我已经简化了路径]

我已经尝试了我认为显而易见的方法,但似乎没有任何效果。我能想到的就是我正在构建 C,但错误指的是在我看来像是 C++ 条目的内容。代码主要是用 Rust(假装是 C)编写的,并带有 SWIG 生成的标准垫片。

任何人都可以告诉我,或者至少给我一些如何进一步调查的想法吗?

Rust 代码

如果我删除标记为“删除我”的两行,那么一切都会正常。请注意,

new_engine()
没有在任何地方被调用。

use std::sync::{Arc, Mutex};
pub struct UserHandle {
    ptr: Arc<Mutex<UserData>>, // delete me
}
pub struct UserData {}
#[no_mangle]
pub unsafe extern "C" fn new_engine() -> *mut UserHandle {
    Box::into_raw(Box::new(UserHandle {
       ptr: (Arc::new(Mutex::new(UserData {}))), // delete me
    }))
}
#[no_mangle]
pub unsafe extern "C" fn get_answer() -> std::ffi::c_int { 57 }

货物档案

[package]
name = "exper2"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"] 

Android 主要活动

崩溃发生在

System.loadLibrary("exper2");
,因此它永远无法调用
get_answer()

package com.example.experiment1;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import exper2.*;

public class MainActivity extends AppCompatActivity {
    private final static String TAG = "exper2";

    static {
        try {
            Log.d(TAG, "loading library [Java]...");
            System.loadLibrary("exper2");
            Log.d(TAG, "loaded library [Java].");
        } catch (Exception e) {
            Log.e(TAG, "exception in load library [Java]: " + e);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "looking for answer [Java]...");
        int answer = exper2.get_answer();
        Log.d(TAG, "answer is " + answer + " [Java]...");
        TextView textView = (TextView) findViewById(R.id.answerText);
        textView.setText("The answer is " + answer);
    }
}

SWIG 接口文件

%module exper2
%{
#include "cbindgen/exper2.h"
%}
%include "cbindgen/exper2.h"

构建脚本

构建动态库后,您可以使用 Android studio 构建 Java,然后运行它。

LIBID=$1

GITDIR="$HOME/git"
export ARCH=aarch64-linux-android
case $LIBID in
    exper2)
        RUSTID=exper2
        REPO=hypoboleus
        ANDAPP=Experiment1
        ;;
    *)
        echo "parameter missing or unknown \"'$LIBID'\", valid hypoboleus or exper2"
        exit 1
        ;;
esac
RUSTID2=${RUSTID//-/_}
TARGETBASE=$GITDIR/$REPO/$RUSTID/target
TARGETDIR=$TARGETBASE/$ARCH/release

export BASE2=$GITDIR/$REPO/$RUSTID
export APPBASE=$GITDIR/$REPO/$ANDAPP
export APPMAIN=$APPBASE/app/src/main
export ANDROID_HOME=/work/android/sdk
export NDK_VERSION=25.2.9519653
export API=33
export NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
export TOOLCHAIN=$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
export CC=$TOOLCHAIN/bin/clang
export AR=$TOOLCHAIN/bin/llvm-ar
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib

cd $BASE2
echo 'base for rust' $BASE2 ', target dir for rust build' $TARGETDIR
# rm -rf $TARGETBASE
mkdir -p $TARGETDIR
RUSTEX_ANDR=$TARGETDIR/lib${RUSTID2}.a
# rm -f $RUSTEX_ANDR
cargo build --target $ARCH --target-dir $TARGETBASE --release --lib
echo 'archive to' $RUSTEX_ANDR
if [[ ! -f $RUSTEX_ANDR ]]; then
    echo "no library file" $RUSTEX_ANDR
    ls $TARGETDIR/lib*
    exit 1
fi

CBINDGEN_DIR=$BASE2/cbindgen/
rm -rf $CBINDGEN_DIR
mkdir -p $CBINDGEN_DIR
cbindgen $BASE2/src/lib.rs --output $CBINDGEN_DIR/${LIBID}.h --lang c

LIBDIR=$APPMAIN/java/$LIBID
echo 'library is called' $LIBID ', stored in' $LIBDIR
rm -rf $LIBDIR
mkdir -p $LIBDIR
swig -outdir $LIBDIR -java -package $LIBID $BASE2/$LIBID.i

SODIR=$APPMAIN/jniLibs/arm64-v8a
rm -rf $SODIR
mkdir -p $SODIR
SONAME=lib${LIBID}.so
echo 'dynamic library to' $SODIR/$SONAME

$CC -target $ARCH-clang -nostartfiles -shared $BASE2/${LIBID}_wrap.c $RUSTEX_ANDR -lm -lz -o $SODIR/$SONAME -I $BASE2 -fPIC
c rust swig entry-point android-native-library
1个回答
0
投票

最后,我恢复到了 NDK 22 版本。

我之前的版本使用了版本 22,并且可以正常工作。所以我从 Android 网站下载了 NSK 版本 22 并重新构建了我的应用程序,它成功了。

这是一种解决方法,而不是正确的解决方案,但它现在对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.