2014-09-03 12 views
9

Ho un'app con 2 librerie native. 1st funziona molto più velocemente su ARMv7 quindi ho la versione sia per ARMv7 che per ARMv5. 2nd funziona allo stesso modo su entrambe le piattaforme, quindi viene fornita solo la libreria ARMv5.Android L Preview non ricerca le librerie native nella cartella "armeabi" (UnsatisfiedLinkError)

cartella My libreria nativa si presenta così:

/jniLibs/ 
    | 
    +---armeabi/ 
    |  | 
    |  +---libFirstLibrary.so 
    |  +---libSecondLibrary.so 
    | 
    +---armeabi-v7a/ 
      | 
      +---libFirstLibrary.so 

L'applicazione funziona bene su tutti i dispositivi e le versioni di Android in produzione.

Quando ho provato sul mio Nexus 5 con L-anteprima (martello-lpv79-anteprima-ac1d8a8e.tgz), ottengo questo errore:

java.lang.UnsatisfiedLinkError: Couldn't load SecondLibrary from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.package-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.package-1, /vendor/lib, /system/lib]]]: findLibrary returned null 
    at java.lang.Runtime.loadLibrary(Runtime.java:358) 
    at java.lang.System.loadLibrary(System.java:610) 

Il problema è che, nonostante il fatto Nexus 5 ha CPU_ABI impostato su armeabi-v7a e CPU_ABI2 impostato su armeabi, L-Preview utilizza solo il valore CPU_ABI e cerca "SecondLibrary" solo nella cartella "armeabi-v7a" e si blocca in quanto non è presente.

Quando copio il file .so anche nella cartella "armeabi-v7a", tutto va bene ma l'APK è di 3,5 MB più grande che non mi piace molto.

È solo un bug di Android L-Preview o di qualche "nuova funzionalità"?

risposta

5

Per quanto ne so, questo è sempre stato il comportamento previsto, e sono perplesso sul motivo per cui questo ha funzionato per voi prima.

Il linker non visualizza il file APK completo su ogni chiamata a loadLibrary; al contrario, le librerie native corrette vengono estratte quando l'APK è installato. Viene usata una sola directory di architettura, quindi se trova lib/armeabi-v7a non cercherà nemmeno lib/armeabi.

C'è un problema noto su alcune versioni precedenti di Android (4.0.3 e precedenti) in cui l'armeabi può essere usato accidentalmente invece di armeabi-v7a, anche se, non è sicuro se questo è ciò che rende questo sembra funzionare per voi.

Vedere ad es. https://android.googlesource.com/platform/ndk/+/532389e89c/docs/text/CPU-ARCH-ABIS.text per una spiegazione ufficiale di questo (sezione "III. Gestione ABI sulla piattaforma Android", in particolare sottosezione III.3 e la nota alla fine della sottosezione III.1).

EDIT: Sembra che il gestore di pacchetti possa installare alcuni file dalla directory ABI secondaria anche se la directory ABI primaria esisteva, su versioni Android fino a kitkat. http://albin.abo.fi/~mstorsjo/hellojni-test-abis.zip è la fonte del mio esempio di prova e http://albin.abo.fi/~mstorsjo/hellojni-test-abis.apk è un file binario di esso. Questo esempio crea quattro librerie native, libgello-jni.so, libhello-jni.so, libhello-jni2.so e libtello-jni.so. Questi file sono costruiti per tutti ABI, ma in armeabi-v7a, ho rimosso tutti i file tranne libhello-jni.so - elenca il file (per le directory architettura ARM) si presenta quindi come questo:

lib/armeabi/libgello-jni.so 
lib/armeabi/libhello-jni.so 
lib/armeabi/libhello-jni2.so 
lib/armeabi/libtello-jni.so 
lib/armeabi-v7a/libhello-jni.so 

Su installazione su un dispositivo kitkat armeabi-v7a , questo installa libhello-jni.so dalla directory armeabi-v7a e libhello-jni2.so e libgello-jni.so dall'indirizzario armeabi - ma l'libtello-jni.so non è installato affatto. Quali file vengono installati sembrano dipendere dai nomi e dall'ordine all'interno dell'APK. Quindi, a seconda dei nomi dei file, potresti aver avuto fortuna prima e questo ha funzionato, anche se la documentazione dice esplicitamente che non dovrebbe funzionare. Nell'anteprima di Android-L questa incoerenza sembra essere stata corretta.

+0

In generale si, ma quasi tutti i dispositivi supportano due ABI. Nel mio caso, Nexus 5 supporta: 'CPU_ABI = armeabi-v7a' e' CPU_ABI2 = armeabi'. Lo stesso meccanismo è usato per i dispositivi Intel in cui ABI primario è 'x86', ma secondario è' armeabi', quindi la mia app funziona bene anche su dispositivi Intel anche se non esiste una libreria nativa nella cartella 'x86'. Secondo me, non c'è motivo per cui questo effetto non funzioni anche su L-Preview. – xsveda

+1

Sì, ma il gestore pacchetti controlla solo le librerie nella directory ABI secondaria se non ne sono state trovate nella directory ABI primaria. La documentazione che ho linkato dice: "il servizio gestore pacchetti eseguirà la scansione di .apk e cercherà qualsiasi libreria condivisa del modulo: lib//lib .so [...] Se ne viene trovato uno, viene copiato sotto' $ APPDIR/lib/lib .so' [...] Se non viene trovato nessuno e viene definito un ABI secondario, il servizio esegue la scansione delle librerie condivise del modulo: lib//lib . così". Quindi se la directory ABI primaria non è vuota, non controllerà il secondario. – mstorsjo

+0

Ecco cosa intendevo nella mia risposta originale: estrae sempre e solo da una singola directory di architettura, che può essere l'ABI primario o secondario. – mstorsjo

Problemi correlati