Я пытаюсь динамически загрузить собственную встроенную библиотеку C, которая встроена в библиотеку .NET во время сборки и используется в приложении Xamarin-Android.
Процесс, который я хочу выполнить:
- Я собираю библиотеку .NET и встраиваю в нее библиотеку C. - Работает
- Я создаю приложение Xamarin для Android, которое использует мою библиотеку .NET. - Работает
- . Во время выполнения .NET извлекает библиотеку C из папки
files
моего приложения. - Работает - После извлечения библиотеки C я динамически загружаю ее, используя
dlopen
. ,- Сбой
Как указано выше, последние шаги завершаются неудачно с сообщением такого типа:
library /data/user/0/com.companyname.namespace/files/mylibrary.so" needed or dlopened by "(unknown)" is not
accessible for the namespace: [name="(anonymous)", ld_library_paths="",
default_library_paths="/data/app/com.companyname.namespace-O7aSwdg3bwneAoiHpkw1zg==/lib/arm64:/data/app/com.companyname.namespace-O7aSwdg3bwneAoiHpkw1zg==/base.apk!/lib/arm64-v8a", permitted_paths=""]
Теперь я знаю, что из API 24 политика Android изменилась назапретить разработчикам загружать собственные библиотеки, которые не являются частью NDK (см. этот выпуск changelog ).
Однако, согласно этого блога и этого другогоблог кажется, что они больше пытаются отговорить людей от этого, чем от того, чтобы полностью предотвратить это, и поэтому то, что я пытаюсь добиться звучания, возможно.
Я попробовал то, что предлагает первый блог, разницу междуэто и мой случай, когда я использую C # для вызова android_create_namespace
и android_dlopen_ext
, а также для создания структур. Вызов android_create_namespace
, кажется, работает, когда я получаю адрес, однако вызов android_dlopen_ext
возвращает NULL, что бы я ни пытался.
См. Код ниже, AndroidDlopen
- основная функция, в которой возникает проблема:
internal static class AndroidNative
{
private const string LibName = "libandroid";
private const int ANDROID_DLEXT_USE_NAMESPACE = 0x200;
private const int RTLD_LOCAL = 0x0;
private const int RTLD_NOW = 0x00002;
private const int RTLD_LAZY = 0x00001;
[DllImport(LibName)]
public static extern int __android_log_print(int prio, string tag, string fmt);
[StructLayout(LayoutKind.Sequential)]
public struct AndroidDlextinfo
{
public ulong Flags;
public int LibraryFd;
public long LibraryFdOffset;
public IntPtr LibraryNamespace;
public int RelroFd;
public IntPtr ReservedAddr;
public uint ReservedSize;
}
public enum AndroidNamespaceType : ulong
{
Regular = 0,
Isolated = 1,
Shared = 2,
GreyListEnabled = 0x08000000,
SharedIsolated = Shared | Isolated
};
[DllImport(LibName, EntryPoint = "android_create_namespace", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr AndroidCreateNamespace(string name, string ldLibraryPath, string defaultLibraryPath,
AndroidNamespaceType type, string permittedWhenIsolatedPath,
IntPtr parent);
[DllImport(LibName, EntryPoint = "android_dlopen_ext", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr androidDlopenExt(string filename, int flags, AndroidDlextinfo info);
public static IntPtr AndroidDlopen(string name)
{
string chirpAssemblyFolder = ChirpDataHandler.ChirpUserFolder;
IntPtr chirpNamespace = AndroidCreateNamespace("trustme", "/system/lib64/", "/system/lib64/",
AndroidNamespaceType.SharedIsolated, "/system/:/data/:/vendor/",
IntPtr.Zero);
AndroidDlextinfo androidDlextinfo = new AndroidDlextinfo
{
Flags = ANDROID_DLEXT_USE_NAMESPACE,
LibraryNamespace = chirpNamespace,
};
IntPtr handle = androidDlopenExt(Path.Combine(chirpAssemblyFolder, name), RTLD_NOW, androidDlextinfo);
return handle;
}
}
Я знаю, что это было бы возможно, если бы я включил библиотеку C в сборку приложения для Android, но в моем случае это не вариант.
Так что я бы хотелхотелось бы знать, возможно ли в конце то, что я делаю, или нет, и если да, чтобы получить некоторую помощь, чтобы выяснить, что не так в том, что я делаю. Спасибо!
Ссылки: