我正在尝试动态加载在Xamarin-Android应用中使用的,在构建时嵌入在.NET库中的自定义本机C库。
我要执行的过程是:
- 我构建.NET库并将C库嵌入其中。 -有效
- 我为使用我的.NET库的Android开发了Xamarin应用。 -有效
- 在运行时,.NET将C库提取到我的应用的
files
文件夹-Works - 提取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)。
但是,根据this blog和this other blog看来,他们似乎更多是在劝说人们不要这样做,而不是完全阻止这样做,因此我正在尝试实现声音。
我尝试了第一个博客的建议,它与案例的区别在于我正在使用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/",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应用程序的构建中,这是有可能的,但就我而言,此解决方案不是一个选择。
因此,我想知道最后我在做什么是否可行,如果可以,获得一些帮助以找出我在做什么的地方出了问题。谢谢!
参考文献: