2012-07-15 28 views
6

Tôi cố gắng để tải hai thư viện được chia sẻ trong ứng dụng Android của tôi qua loadLibrary gọi:Liên kết với thư viện chia sẻ phiên bản trong Android NDK

System.loadLibrary("mywrapper"); 
System.loadLibrary("crypto"); 

tôi tiếp tục chạy bắt 'UnsatisfiedLinkError. Đây là một phiên bản chi tiết hơn của lỗi.

Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1969]: 
    130 could not load needed library 'libcrypto.so.1.0.0' for 
    'libmywrapper.so' (load_library[1111]: Library 'libcrypto.so.1.0.0' not found) 

Bất kỳ ý tưởng nào?

Sau một thời gian, tôi phát hiện ra rằng Android không hỗ trợ thư viện được phiên bản. Có ai phải đối mặt với cùng một vấn đề?

Trả lời

2

Có vẻ như Android có vấn đề với việc tải thư viện phiên bản. Vấn đề hiện tại là do thư viện tên trong trường hợp của tôi là libcrypto.so.1.0.0. Thậm chí nếu bạn đổi tên thư viện và cố gắng tải nó như là một thư viện được dựng sẵn trong một tệp android làm cho nó không thành công (Nó phải là vì tên thư viện bằng cách nào đó được nhúng vào tệp. Và bất kỳ thư viện nào liên kết với nó dự kiến ​​sẽ là được liên kết với một thư viện có cùng tên)

Tôi hy vọng có nhiều cách khác ngoài kia khi nói đến việc xử lý các thư viện có tên phiên bản trong Android.

Hiện tại, tôi đang tránh tất cả vấn đề cùng nhau bằng cách sử dụng các thư viện tĩnh của openssl và liên kết chúng với thư viện được chia sẻ của riêng tôi.

2

Năm 2014 và vẫn không hỗ trợ cho lib được chia sẻ phiên bản. Vì vậy, tôi đã thực hiện một kịch bản để vá SONAME. Chỉ cần chỉ kịch bản lệnh vào thư mục đầu vào nơi tất cả các phiên bản libs được đặt. Sau đó kiểm tra đầu ra dir "unver".

#!/bin/bash 

DIR="$1" 

if [ "$DIR" == "" ]; then 
    echo "Usage: fix-soname.sh <target dir>" 
    exit 
fi 

if [ ! -d $DIR ]; then 
    echo "Not found: $DIR" 
    exit 
fi 

OUT="$DIR/unver" 
echo "Input=$DIR" 
echo "Output=$OUT" 

CWD=$(pwd) 
cd $DIR 

# prep dirs 
mkdir -p $OUT 
rm -f -R $OUT/* 

# rename libs and copy to out dir 
find "$DIR" -type f -name '*.so*' | while read FILE; do 

    NAME=$(basename "$FILE") 
    SONAME=$NAME 

    while read SYMLINK; do 
     X=$(basename "$SYMLINK") 
     #echo "$X (${#X}) -> $NAME (${#NAME})" 
     if [ "${#X}" -lt "${#SONAME}" ]; then 
      SONAME=$X 
     fi 
done<<EOT 
`find -L $DIR -samefile $FILE` 
EOT 

    #echo $SONAME 
    cp -f $SONAME $OUT/ 
done 

# patch libs in out dir 
find "$OUT" -type f -name '*.so*' | while read FILE; do 

    # get file name without path 
    NAME=$(basename "$FILE") 

    # extract SONAME from shared lib 
    SONAME=`readelf -d $FILE | grep '(SONAME)' | grep -P '(?<=\[)(lib.*?)(?=\])' -o` 

    #echo "$NAME [$SONAME]" 

    # patch SONAME if required 
    if [ "$NAME" != "$SONAME" ]; then 
     L1=${#NAME} 
     L2=${#SONAME} 
     LDIFF=$((L2-L1)) 
     #echo "$NAME [$SONAME] ($LDIFF)" 

     if [ "$LDIFF" -gt "0" ]; then 
      SONEW=$NAME 
      for ((c=1; c<=$LDIFF; c++)); do 
       SONEW+="\x00" 
      done 
      echo "$NAME [$SONAME] -> $SONEW ($LDIFF)" 
      rpl -R -e "$SONAME" "$SONEW" $OUT 
     fi 
    fi 
done 

cd $CWD 
+0

nó không hoạt động đối với tôi ... tôi chạy nó trên thư mục nguồn mở openssl, với các tệp nhị phân được biên dịch và đầu ra thư mục 'unver' là giống hệt với binary binary libcrypto.so – Giovani

+0

Bạn có thể bỏ ghi chú # doo trong tập lệnh và xem nơi nào đó đã xảy ra sự cố. – sviborg

+0

Hoặc sử dụng [patchelf] (https://www.mankier.com/1/patchelf) để khắc phục. –

4

Tôi đã gặp phải vấn đề tương tự khi xây dựng libwebsockets cho Android, cần liên kết với OpenSSL. Tôi sử dụng libssl.so làm ví dụ. Bạn nên làm tương tự cho các tệp .so có liên quan.

Before: 
 
[email protected]:~$ objdump -p libssl.so | grep so 
 
libssl.so:  file format elf32-little 
 
    NEEDED    libcrypto.so.1.0.0 
 
    NEEDED    libdl.so 
 
    NEEDED    libc.so 
 
    SONAME    libssl.so.1.0.0 
 

 
After 
 
[email protected]:~$ rpl -R -e .so.1.0.0 "_1_0_0.so" libssl.so 
 
Replacing ".so.1.0.0" with "_1_0_0.so" (case sensitive) (partial words matched) 
 
. 
 
A Total of 2 matches replaced in 1 file searched. 
 
[email protected]:~$ objdump -p libssl.so | grep so 
 
libssl.so:  file format elf32-little 
 
    NEEDED    libcrypto_1_0_0.so 
 
    NEEDED    libdl.so 
 
    NEEDED    libc.so 
 
    SONAME    libssl_1_0_0.so 
 

 
And don't forget to change file name "libssl.so" to "libssl_1_0_0.so".

Các công trình hack. Tôi đã chạy ứng dụng Android để chứng minh điều đó. Xem rant của tôi tại http://computervisionandjava.blogspot.com/2015/05/trouble-with-versioned-shared-libraries.html.

+0

Tôi không thể tìm cách làm việc với các tệp .so, nhưng tôi có thể chỉnh sửa tệp bằng VIM và thay thế chuỗi đó ở đó. Tuyệt vời hack. Cảm ơn! – Xample

Các vấn đề liên quan