2014-09-03 6 views
9

Ich habe eine App mit 2 nativen Bibliotheken. 1. funktioniert viel schneller auf ARMv7, so habe ich Version für ARMv7 und ARMv5. 2. funktioniert auf beiden Plattformen gleich, daher wird nur die ARMv5-Bibliothek bereitgestellt.Android L Preview sucht nicht nach nativen Bibliotheken im "armeabi" -Ordner (UnatisfiedLinkError)

Meine Mutter Library-Ordner wie folgt aussieht:

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

Die App funktioniert gut auf allen Geräten und Android-Versionen in der Produktion.

Wenn ich es auf meinem Nexus 5 mit L-Vorschau getestet (Hammerhai-lpv79-Vorschau-ac1d8a8e.tgz), bekomme ich diesen Fehler:

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) 

Das Problem ist, dass trotz der Tatsache, Nexus 5 hat CPU_ABI eingestellt auf armeabi-v7a und CPU_ABI2 eingestellt auf armeabi, verwendet L-Preview nur CPU_ABI value und sucht nach "SecondLibrary" nur im "armeabi-v7a" -Ordner und stürzt ab, da es nicht da ist.

Wenn ich die .so-Datei auch in den Ordner "armeabi-v7a" kopiere, ist alles in Ordnung, aber die APK ist 3,5 MB größer, was ich nicht wirklich mag.

Ist es nur ein Fehler von Android L-Preview oder ein "neues Feature"?

Antwort

5

Soweit ich weiß, war dies immer das beabsichtigte Verhalten, und ich bin verwundert, warum dies für Sie schon einmal funktioniert hat.

Der Linker durchsucht nicht die vollständige APK-Datei bei jedem loadLibrary-Aufruf - stattdessen werden die richtigen systemeigenen Bibliotheken extrahiert, wenn das APK installiert wird. Es wird nur ein einziges Architekturverzeichnis verwendet. Wenn es lib/armeabi-v7a gefunden hat, sucht es nicht einmal nach lib/armeabi.

Es gibt ein bekanntes Problem auf einigen älteren Versionen von Android (4.0.3 und früher), wo das armeabi versehentlich anstelle von armeabi-v7a verwendet werden kann, nicht sicher, ob das das ist, was das für Sie zu arbeiten scheint.

Siehe z.B. https://android.googlesource.com/platform/ndk/+/532389e89c/docs/text/CPU-ARCH-ABIS.text für eine offizielle Erklärung dieses (Abschnitt "III. ABI Management auf der Android-Plattform", insbesondere Unterabschnitt III.3 und der Hinweis am Ende des Unterabschnitts III.1).

EDIT: Es scheint tatsächlich, dass der Paketmanager einige Dateien aus dem sekundären ABI-Verzeichnis installieren konnte, obwohl das primäre ABI-Verzeichnis existierte, auf Android-Versionen bis zu kitkat. http://albin.abo.fi/~mstorsjo/hellojni-test-abis.zip ist die Quelle für mein Testbeispiel, und http://albin.abo.fi/~mstorsjo/hellojni-test-abis.apk ist eine binäre davon. In diesem Beispiel werden vier native Bibliotheken erstellt: libgello-jni.so, libhello-jni.so, libhello-jni2.so und . Diese Dateien werden für alle ABIs gebaut, aber in armeabi-v7a habe ich alle Dateien außer libhello-jni.so entfernt - die Dateiliste (für die ARM-Architektur Verzeichnisse) sieht somit wie folgt:

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 

Bei der Installation auf einem kitkat armeabi-v7a Gerät , dies installiert libhello-jni.so aus dem Verzeichnis armeabi-v7a und libhello-jni2.so und libgello-jni.so aus dem Verzeichnis armeabi - aber ist überhaupt nicht installiert. Welche Dateien installiert sind, hängt von den Namen und der Reihenfolge innerhalb der APK ab. Abhängig von Ihren Dateinamen haben Sie vielleicht schon einmal Glück gehabt und das hat funktioniert - auch wenn die Dokumentation explizit besagt, dass es nicht funktionieren soll. In der Android-L-Vorschau scheint diese Inkonsistenz korrigiert worden zu sein.

+0

Im Allgemeinen ja, aber fast alle Geräte haben Unterstützung für zwei ABIs. In meinem Fall unterstützt Nexus 5: 'CPU_ABI = armeabi-v7a' und' CPU_ABI2 = armeabi'. Der gleiche Mechanismus wird verwendet, d. H. Für Intel-Geräte, wo primäre ABI 'x86' ist, aber sekundär 'armeabi' ist, so dass meine App auch auf Intel-Geräten gut läuft, obwohl keine native Bibliothek in' x86'-Ordner vorhanden ist. Meiner Meinung nach gibt es keinen Grund, warum das nicht auch bei L-Preview funktionieren sollte. – xsveda

+1

Ja, aber der Paketmanager sucht nur nach Bibliotheken im sekundären ABI-Verzeichnis, wenn keine im primären ABI-Verzeichnis gefunden wurden. Die Dokumentation, die ich verlinkte, sagt: "Der Paket-Manager-Service wird die .apk scannen und nach einer freigegebenen Bibliothek des Formulars suchen: lib//lib .so Wenn [...] gefunden wird, wird es unter' kopiert $ APPDIR/lib/lib .so' Wenn keiner gefunden wird und ein sekundärer ABI definiert ist, sucht der Service nach freigegebenen Bibliotheken des Forms: lib//lib . damit". Wenn also das primäre ABI-Verzeichnis nicht leer ist, wird das sekundäre ABI-Verzeichnis nicht überprüft. – mstorsjo

+0

Das ist also, was ich in meiner ursprünglichen Antwort gemeint habe - es extrahiert immer nur ein einziges Architekturverzeichnis - das kann entweder der primäre oder der sekundäre ABI sein. – mstorsjo