Загрузка нескольких общих библиотек во время выполнения не работает в Android

Я использую cmake для создания моих общих библиотек в Android Studio. Библиотеки создаются и связываются правильно, и я могу видеть все свои библиотеки в Apk в lib/armeabi-v7a.

Библиотеки связаны следующим образом:

  • Lib1
    • Lib2
      • Lib3
        • Lib4
        • Lib5

Я загрузил свой Lib1, позвонив System.loadLibrary("lib1");

Я могу звонить в Lib1, но как только Lib1 пытается получить доступ к Lib2, я получаю сообщение о том, что Lib2 не был загружен.

Затем я решил, что мне нужно загрузить другие библиотеки, поэтому я сделал следующие вызовы, но в итоге получил то же самое распространенное сообщение "Lib2 не загружен".

System.loadLibrary("lib5");
System.loadLibrary("lib4");
System.loadLibrary("lib3");
System.loadLibrary("lib2");
System.loadLibrary("lib1");

Почему Lib1 не сможет вызвать Lib2? Распакованы ли дополнительные общие библиотеки в месте, которое вызывает сбой загрузки библиотеки?

Я хотел бы отметить, что мои библиотеки правильно загружались до перехода на использование cmake. Я полагаю, что ранее я вручную компилировал свои библиотеки и сохранял их в каталогах /jniLibs и /assets в своем проекте Android Studio, но это было некоторое время назад, поэтому моя память не совсем ясна в деталях.

1 ответ

Поскольку ваши изменения вступают в силу, я думаю, что это не случайность, а установка двоичных файлов в неправильное место. (Я сам иногда загружал в jniLibs/armeabi-v7a потом понял, что я тестирую 64-битный APK, который опирается на jniLibs/arm64-v8a, Или наоборот при установке apk с двойной архитектурой на 32-разрядное устройство Android.)

Я думаю, что мы можем исключить неразрешенный символ также во время загрузки, потому что он обычно говорит вам об этом в adb logcat

Я вспоминаю, что когда я видел эту проблему в прошлом, обычно это была проблема с сонам lib2. Хотя ПК Linux может работать с чем-то вроде liblib2.so.1Android, кажется, требует, чтобы все сонамы заканчивались .so

Чтобы проверить soname на lib2, запустите readelf -a liblib2.so, Если он кажется неправильным, как я описал, переделайте свою сборку NDK и убедитесь, что -Wl,-soname,liblib2.so добавляется во время ссылки.

Кроме того, запустить readelf -a liblib1.so и убедитесь, что его ссылка на liblib2.so использует новое имя сына, например (NEEDED) Shared Library: [liblib2.so], Вам также может понадобиться повторно связать liblib1.so.

Я хотел бы отметить, что мои библиотеки правильно загружались до перехода на использование cmake.

Я предполагаю, что CMake использовался для этапа сборки NDK, а не Java, что могло бы объяснить изменение сонама.

Примечание: немного сбивает с толку, что вы добавляете дополнительную "lib" в имена каждой библиотеки. Было бы легче общаться, если бы вы использовали пример, который сделал System.loadLibrary("1"), System.loadLibrary("2")

В зависимости от вашего файла Gradle это может быть связано с тем, что AS выполняет только последний файл cmake, указанный в externalNativeBuild заявление.

Вы можете заглянуть внутрь своего APK, чтобы проверить, какие библиотеки на самом деле собираются и собираются. Если вы измените расширение apk на.zip, то разархивируйте и посмотрите на lib каталог, вы найдете список каталогов сборки, которые содержат файлы.so. Если вы не видите.so, соответствующий System.loadLibrary(<libName>); позвоните, вы получите ошибки во время выполнения.

Проблема, которая вызвала у меня похожую проблему , заключается в том, что я пытался использовать несколько файлов cmake, соответствующих каждой библиотеке, которую я хотел включить, используя externalNativeBuild в файле сборки моего приложения Gradle вот так:

externalNativeBuild {
    cmake {
        path "CMakeLists1.txt"
        path "CMakeLists2.txt"
    }
}

И я заметил, что выполняется только последний CMakeLists.txt, указанный в этом операторе. Это привело только к одному.so файлу для вывода на мои APK lib каталог, а не оба, как я хотел. Я считаю, что намерение AS состоит в том, чтобы ссылаться только на один файл cmake в этом утверждении. Если вы ссылаетесь больше, как я, вероятно, он только строит последний, так что остальные (в вашем случае, все, что после "lib1") будут отсутствовать.

Другие вопросы по тегам