Ответ 1
Согласно https://groups.google.com/forum/?fromgroups#!msg/android-ndk/J3lzK4X--bM/4YaijymZy_AJ
Да, и это документированное поведение: вы должны явно загружать библиотеки в обратную зависимость. [...] Это ограничение системы.
В двух словах динамический компоновщик ничего не знает о вашем приложении (например, где живут его библиотеки), он знает только о значении LD_LIBRARY_PATH, которое было установлено при создании процесса. Когда вы запускаете приложение для Android, вы действительно разворачиваете процесс Zygote, вы не создаете новый, поэтому путь поиска библиотеки является исходным и не включает в себя каталог приложений/данных/данных//lib/, где ваши родные библиотеки живут. Это означает, что dlopen ( "libfoo.so" ) не будет работать, потому что будет выполняться поиск только /system/lib/libfoo.so.
Когда вы вызываете System.loadLibrary( "foo" ) из Java, среда VM знает каталог приложения, поэтому он может переводить "foo" в "/data/data//lib/libfoo.so", а затем вызвать dlopen() с этим полным путем, который будет работать.
Это libfoo.so ссылается на "libbar.so", тогда динамический компоновщик не сможет найти последний.
Добавьте к этому, что даже если вы обновите LD_LIBRARY_PATH из собственного кода, динамический компоновщик не увидит новое значение. Для разных низкоуровневых причин динамический компоновщик содержит свою собственную копию программной среды, как это было при создании процесса (не разветвлено). И просто нет возможности обновить его из собственного кода. Это по дизайну, и изменение этого будет иметь серьезные ограничения безопасности. Для записи это также то, как работает динамический компоновщик Linux, это заставляет любую программу, которая нуждается в пути поиска пользовательской библиотеки, использовать оболочку script для запуска своего исполняемого файла (например, Firefox, Chrome и многие другие).
Я отправил по электронной почте автора, спрашивая, где это задокументировано.
Tor Lillqvist продолжает обходное решение: https://groups.google.com/d/msg/android-ndk/J3lzK4X--bM/n2zUancIFUEJ
Чтобы быть более подробным, что делает эта функция lo_dlopen():
- Ищет, где находится общий объект. Он ищет набор каталогов, переданных ему кодом Java. Код Java выглядит на LD_LIBRARY_PATH и добавляет к нему каталог приложений lib.
- Открывает найденный файл общих объектов и читает в нем структуры ELF. Не все, но достаточно, чтобы узнать, какие общие объекты ему нужны (DT_NEEDED, как показано в файле arm-linux-androideabi-readelf -d). Он называет себя рекурсивно на необходимых общих объектах.
- Только после этого, то есть после проверки того, что все необходимые другие общие объекты были загружены, он вызывает реальный dlopen() для найденного полного пути к общему объекту.
Вы можете найти его код в http://cgit.freedesktop.org/libreoffice/core/tree/sal/android/lo-bootstrap.c?id=5510127e89d6971a219ce3664e4631d6c6dda2b1
UPDATE. Согласно http://code.google.com/p/android/issues/detail?id=34416, этот код был интегрирован в Android по состоянию на декабрь 2012 года. Yay! Зависимости загружаются автоматически для устройств с уровнем API 18 и выше. Если вы поддерживаете более старые уровни API, чем это, вам все равно нужно перечислять зависимости.