Laden von freigegebenen libs, die von anderen freigegebenen libs abhängen

Problem:

Ich libgstreamer-0.10.so Android-App in Eclipse, die gemeinsame lib libgstreamer-0.10.so (GStreamer-Android NDK Bundle libs kompiliert für Android-8-Plattform) . Ich habe neue Ordner libs/armeabi im Projekt-Stammordner und legte es dort. Auch habe ich alle anderen libs, die mit ihm kam (158 von ihnen) in den gleichen Ordner. Wenn ich das in meinen Hauptaktivitätscode stelle:

 static{ System.loadLibrary("gstreamer-0.10"); } 

Und baue / install / run meine app auf Android-8 Emulator, es wirft diesen Fehler:

 06-15 21:54:00.835: E/AndroidRuntime(402): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1962]: 33 could not load needed library 'libglib-2.0.so' for 'libgstreamer-0.10.so' (load_library[1104]: Library 'libglib-2.0.so' not found) 

Nun, libglib-2.0.so ist im selben Ordner wie libgstreamer-0.10.so , und warum ist es nicht geladen? Ich bekomme, dass Linker versucht, es aus /system/lib und libglib-2.0.so einfach ist nicht da, aber warum ist es nicht Laden es von der Stelle, wo libgstreamer-0.10.so ist?

So ging ich zu entdecken, welche libs libgstreamer-0.10.so hängt davon ab mit diesem Befehl:

 arm-linux-androideabi-readelf -d libgstreamer-0.10.so 

Ergebnisse:

 Dynamic section at offset 0x118b64 contains 29 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libglib-2.0.so] 0x00000001 (NEEDED) Shared library: [libgobject-2.0.so] 0x00000001 (NEEDED) Shared library: [libgthread-2.0.so] 0x00000001 (NEEDED) Shared library: [libgmodule-2.0.so] 0x00000001 (NEEDED) Shared library: [libdl.so] 0x00000001 (NEEDED) Shared library: [libm.so] 0x00000001 (NEEDED) Shared library: [libstdc++.so] 0x00000001 (NEEDED) Shared library: [libc.so] 0x0000000e (SONAME) Library soname: [libgstreamer-0.10.so] 0x00000010 (SYMBOLIC) 0x0 

Erster vier libglib-2.0.so, libgobject-2.0.so, libgthread-2.0.so, libgmodule-2.0.so sind alle im selben Ordner libgstreamer-0.10.so befindet sich in ( /data/data/com.marko.gstreamer_test/lib ) auf dem Gerät.

Logische Lösung:

Also habe ich versucht, diese vier libs zu laden, bevor ich libgstreamer-0.10.so und es funktionierte:

 static{ System.loadLibrary("glib-2.0"); System.loadLibrary("gthread-2.0"); System.loadLibrary("gobject-2.0"); System.loadLibrary("gmodule-2.0"); System.loadLibrary("gstreamer-0.10"); } 

Meine Fragen sind:

  1. Kann ich irgendwie sagen, dass der Linker libs auch aus dem App-Standort lädt? Wie Pfad zu einer Umgebungsvariable hinzufügen oder so etwas wie PATH auf Linux.

  2. Hat meine Lösung einige schlechte Nebenwirkungen? Ich meine, Linker würde das auch tun, bevor es den libgstreamer-0.10.so lädt. Aber wird das irgendwelche Probleme machen?

  3. Kann ich meine libs auf / system / lib Ordner auf unrooted Gerät installieren?

  • Wie fange ich UnzufriedeneLinkError bei der Verwendung von NDK-basierter Bibliothek in einer Android App?
  • Warum gibt Arm-linux-androideabi-gcc Iostream-Fehler
  • Kompilieren von SDL2 für Android
  • Android NDK: Link mit einer vorkompilierten statischen Bibliothek
  • Android NDK / JNI: Aufbau einer gemeinsamen Bibliothek, die von anderen freigegebenen Bibliotheken abhängt
  • Kann keine native Shared Library mit Abhängigkeiten in einer nativen Activity App laden
  • Undefinierte Referenz Zu 'cv :: initModule_nonfree ()' In Android
  • Android: Kann keine Bibliothek laden (94 fehlende wesentliche Tabellen)
  • 2 Solutions collect form web for “Laden von freigegebenen libs, die von anderen freigegebenen libs abhängen”

    Nach https://groups.google.com/forum/?fromgroups#!msg/android-ndk/J3lzK4X–bM/4YaijymZy_AJ

    Ja, und das ist das dokumentierte Verhalten: Sie müssen Bibliotheken in umgekehrter Abhängigkeitsreihenfolge explizit laden. […] Es ist eine Beschränkung des Systems.

    Kurz gesagt, der dynamische Linker weiß nichts über Ihre Anwendung (zB wo seine Bibliotheken leben), es kennt nur den Wert LD_LIBRARY_PATH, der bei der Erstellung des Prozesses gesetzt wurde. Wenn du eine Android-Anwendung anfängst, kannst du den Zygote-Prozess wirklich ausführen, du erschaffst keinen neuen, also ist der Bibliotheks-Suchpfad der erste und schließt nicht dein App / data / data // lib / Verzeichnis ein Ihre Heimatbibliotheken leben. Das bedeutet, dass dlopen ("libfoo.so") nicht funktionieren wird, denn nur /system/lib/libfoo.so wird gesucht.

    Wenn du System.loadLibrary ("foo") von Java nennst, kennt das VM-Framework das Verzeichnis der Applikation, also kann es "foo" in "/data/data//lib/libfoo.so" übersetzen und dann mit dlopen () aufrufen Dieser volle Weg, der funktionieren wird.

    Es libfoo.so Referenzen "libbar.so", dann wird der dynamische Linker nicht in der Lage sein, diese zu finden.

    Fügen Sie hinzu, dass selbst wenn Sie LD_LIBRARY_PATH aus nativem Code aktualisieren, der dynamische Linker den neuen Wert nicht sehen wird. Aus verschiedenen Low-Level-Gründen enthält der dynamische Linker eine eigene Kopie der Programmumgebung, wie es war, als der Prozess erstellt wurde (nicht gegabelt). Und es gibt einfach keine Möglichkeit, es aus nativen Code zu aktualisieren. Dies ist durch Design, und das Ändern würde drastische Sicherheitsbeschränkungen haben. Für die Aufzeichnung ist dies auch, wie der Linux-Dynamic Linker funktioniert, dies zwingt jedes Programm, das einen benutzerdefinierten Bibliothekssuchpfad benötigt, um ein Wrapper-Skript zu verwenden, um seine ausführbare Datei (zB Firefox, Chrome und viele andere) zu starten.

    Ich habe per E-Mail an den Autor gefragt, wo dies dokumentiert ist.

    Tor Lillqvist fährt fort, um einen Workaround bereitzustellen: https://groups.google.com/d/msg/android-ndk/J3lzK4X–bM/n2zUancIFUEJ

    Um ausführlicher zu sein, was die Funktion lo_dlopen () funktioniert:

    • Sucht, wo das gemeinsame Objekt in Frage ist. Es durchsucht eine Reihe von Verzeichnissen, die ihm durch den Java-Code übergeben werden. Der Java-Code sieht LD_LIBRARY_PATH an und fügt das lib-Verzeichnis der App hinzu.
    • Öffnet die gefundene freigegebene Objektdatei und liest die ELF-Strukturen darin. Nicht alle, aber gerade genug, um herauszufinden, welche geteilten Objekte es braucht (die DT_NEEDED diejenigen, die von arm-linux-androideabi-readelf -d angezeigt werden). Es nennt sich rekursiv über die benötigten gemeinsamen Objekte.
    • Erst danach, dh nachdem wir sichergestellt haben, dass alle benötigten anderen freigegebenen Objekte geladen wurden, ruft es das echte dlopen () auf den gefundenen vollständigen Pfadnamen zum freigegebenen Objekt auf.

    Sie finden seinen Code auf http://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-bootstrap.c?id=5510127e89d6971a219ce3664e4631d6c6dda2b1

    UPDATE : Nach http://code.google.com/p/android/issues/detail?id=34416 wurde dieser Code ab Dezember 2012 in Android integriert. Yay!

    1. Ich bin nicht sicher, dass Sie für Java-Apps tun können. Für native Befehlszeilenanwendungen können Sie dies tun, indem Sie LD_LIBRARY_PATH Umgebungsvariable setzen, bevor Sie die Anwendung angeben.

    2. Das ist richtige Lösung. Irgendwo in NDK-Dokumenten ist dies erwähnt, dass Sie alle abhängigen Bibliotheken auf diese Weise laden müssen.

    3. Nein, das kannst du nicht.

    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.