在android N上使用 .so作为apk的第三方库的时候,会发生[添加链接描述](https://blog.csdn.net/weixin_42082222/article/details/104650503)java.lang.UnsatisfiedLinkError:
09-27 12:17:01.280 D/ListenSoundModel( 3635): Load libxxxjni
09-27 12:17:01.292 D/AndroidRuntime( 3635): Shutting down VM
——— beginning of crash
09-27 12:17:01.293 E/AndroidRuntime( 3635): FATAL EXCEPTION: main
09-27 12:17:01.293 E/AndroidRuntime( 3635): Process: com.qualcomm.xxx, PID: 3635
09-27 12:17:01.293 E/AndroidRuntime( 3635): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/xxxApp.apk”],nativeLibraryDirectories=[/data/app-lib/xxxApp, /system/lib64, /vendor/lib64]]] couldn’t find “libxxxjni.so”
09-27 12:17:01.293 E/AndroidRuntime( 3635): at java.lang.Runtime.loadLibrary0(Runtime.java:972)
09-27 12:17:01.293 E/AndroidRuntime( 3635): at java.lang.System.loadLibrary(System.java:1530)
…
09-27 12:17:01.293 E/AndroidRuntime( 3635): at android.os.Handler.dispatchMessage(Handler.java:102)
09-27 12:17:01.293 E/AndroidRuntime( 3635): at android.os.Looper.loop(Looper.java:154)
这在google的变更说明有 介绍
https://developer.android.com/preview/behavior-changes.html#ndk
,
具体是什么原因呢,怎么解决这种问题呢,google给出了一个官方的解决办法(如上链接),这里也给出另外一种方法。
首先,主要原因是google在N上对.so库的加载进行了限制,限制了so库指从部分指定的路径进行加载,不在这个路径的so提示
java.lang.UnsatisfiedLinkError: dlopen failed: library “xxx.so” not found 或
java.lang.UnsatisfiedLinkError: dlopen failed: library “/vendor/lib64/xxx.so” needed or dlopened by “/system/lib64/libnativeloader.so” is not accessible for the namespace “classloader-namespace” 或 其他异常错误提示。
N上对so库加载的搜索路径方式为ld_library_path, runtime path, permit path,不在这个搜索路径下则加载失败。
从代码层面看,主要是类加载器ClassLoader的相关处理,
code1: (loadedApk.java getClassLoader()) check sdk version
// DO NOT SHIP: this is a workaround for apps loading native libraries
// provided by 3rd party apps using absolute path instead of corresponding
// classloader; see
http://b/26954419
for example.
if (mApplicationInfo.targetSdkVersion <= 23) {
libraryPermittedPath += File.pathSeparator + “/data/app”;
}
Code2: (loadedApk.java getClassLoader()) N add a new PermittedPath
String libraryPermittedPath = mDataDir;
Code3: (native_loader.cpp) use the new namespace rule with search path: ld_library_path, runtime path, permit path.
在明白原因之后,
解决办法则是将自己的so加入到允许路径的白名单里面,具体操作为,如果不改代码实现,则导出设备的/vendor/etc/public.libraries.txt 或/etc/public.libraries.txt文件,将so名字添加进去,在push到设备,重启即可。
Android N 版本有个新feature,就是普通应用不能直接引用系统的一些so库了,只能直接引用public.libraries.txt文件中过滤的so库。这个网址有介绍怎么处理。
source.android.com/devices/tec…
具体情况是这样的:我有一个系统权限的apk,这个apk会编译出一些so库放在system/lib目录下面,刚刷机这个apk是可以引用到这些so库的,但我调试的时候直接install这个apk,运行的时候居然直接挂了!!我也是醉了。没想到这个新feature居然影响到我的系统权限的apk。真蛋疼,我可不想每次push这个apk然后重启才生效,一般我都是直接install的,但现在好日子貌似到头了。
一.看看报错信息罗
具体报错的信息如下:
needed
or dlopened by
"/system/lib64/libnativeloader.so"
is not accessible for the namespace
"classloader-namespace"
大概的意思就是应用nativeloader打不开libhaha_utils.so这个so库了,就崩溃了!!好残忍。libhaha_utils.so这个库是用我用Android.mk编译后放在system/lib64下面的。但现在打不开了。
为啥呢?
因为/system/lib64/不在APK查找so库的合法路径啊,合法路径有啥呢?
上面log就有说明啦。下面三个路径都没有找到libhaha_utils.so库,所以就挂了。
ld_library_paths="",
default_library_paths="/system/fake-libs64:/data/app/com.example.haha-1/base.apk!/lib/arm64-v8a", permitted_paths="/data:/mnt/expand:/data/data/com.example.haha
二.那为啥刚刷机时APK可以用,Install这个apk后就不能用了呢?
这个apk可是系统权限的哟,就是apk的清单AndroidManifest中有下面一句
android:sharedUserId="android.uid.system"
正常来说,这种高端apk的permitted_paths是包含system/lib64的,从源码可以知道
/
frameworks
/
base
/
core
/
java
/
android
/
app
/
LoadedApk.java
1 //如果是系统apk并且没有升级过
2 final boolean isBundledApp = mApplicationInfo.isSystemApp()
3 && !mApplicationInfo.isUpdatedSystemApp();
5 String libraryPermittedPath = mDataDir;
6 if (isBundledApp) { //permitted_paths就增加system/lib64
7 // This is necessary to grant bundled apps access to
8 // libraries located in subdirectories of /system/lib
9 libraryPermittedPath += File.pathSeparator +
10 System.getProperty("java.library.path");
11 }
看上面的注释就知道啦,如果是系统apk并且没有升级过的话,so库的搜索路径就会增加一个system/lib64。我去,google搞啥呢,为什么还要限定不能升级。
因为install -r来安装apk就相当于升级,所以刷机时apk可以用,install升级后不能用。
三.那如何解决这个鬼问题呢?
我纯粹是为了调试方便,所以参考google的链接
source.android.com/devices/tec…
google.png
应用可以调用/vendor/etc/public.libraries.txt和/system/etc/public.libraries.txt里面的所有so库,所以哥往这个文件写入libhaha_utils.so,这个库就变成共用的了,任意应用就可以找到这个so库了,终于可以欢快地使用install apk的方式调试啦!!再也不用重启了!!
下面是原生google的图
Paste_Image.png
大概有这么些个so库是共用的。
libandroid.so
libc.so
libdl.so
libEGL.so
libGLESv1_CM.so
......
可以看看原生的这笔提交修改的。
android-review.googlesource.com/#/c/209029/
四.看看源码这个public.libraries.txt文件是咋玩的
在这个源码里面用到这个txt文件
/
system
/
core
/
libnativeloader
/
native_loader.cpp
在LibraryNamespaces类的Initialize()会读取这个文件,将so库设置为公共so库,所谓公共so库,就是这个so库谁都能用啦。
1 static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
2 static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
3 void Initialize() {
4 ..................
5 std::vector<std::string> sonames;
6 ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
7 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
8 public_libraries_ = base::Join(sonames, ':');
9 .............
10 }
这个方法时什么时候调用的呢?大概过下流程罗。
首先在创建一个虚拟机的时候,初始化NativeLoader,这个NativeLoader,顾名思义,就是用来装载so库的。
/
art
/
runtime
/
java_vm_ext.cc
1 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
2 ................
3 // Initialize native loader. This step makes sure we have
4 // everything set up before we start using JNI.
5 android::InitializeNativeLoader();
6 ..............
然后进入native_loader,进行初始化
/system/core/libnativeloader/native_loader.cpp
1 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
3 void InitializeNativeLoader() {
4 g_namespaces->Initialize();
初始化是调用LibraryNamespaces类的Initialize完成公共so库的赋值,哈哈哈,搞定!!
1 void Initialize() {
2 ..................
3 std::vector<std::string> sonames;
4 ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
5 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
6 public_libraries_ = base::Join(sonames, ':');
7 .............
8 }
总结:
1.Android N 不能直接调用系统的一些私有库了,公用的库都定义在public.libraries.txt里面。
2.系统应用刚刷机是能够调用system/lib64下的库,但通过install升级该应用时,应用打开会挂。因为升级后permitted_paths就不再包含system/lib64了。所以我们可以将apk要用到的库名称写到public.libraries.txt中去解决快速调试问题。
在android N上使用 .so作为apk的第三方库的时候,会发生java.lang.UnsatisfiedLinkError:
09-27 12:17:01.280 D/ListenSoundModel( 3635): Load libxxxjni
09-27 12:17:01.292 D/AndroidRuntime( 3635): Shutting down VM
——— beginning of crash
09-27 12:17:01.293 E/AndroidRuntime( 3635): FATAL EXCEPTION: main
09-27 12:17:01.293 E/AndroidRuntime( 3635): Process: com.qualcomm.xxx, PID: 3635
09-27 12:17:01.293 E/AndroidRuntime( 3635): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/xxxApp.apk”],nativeLibraryDirectories=[/data/app-lib/xxxApp, /system/lib64, /vendor/lib64]]] couldn’t find “libxxxjni.so”
09-27 12:17:01.293 E/AndroidRuntime( 3635): at java.lang.Runtime.loadLibrary0(Runtime.java:972)
09-27 12:17:01.293 E/AndroidRuntime( 3635): at java.lang.System.loadLibrary(System.java:1530)
…
09-27 12:17:01.293 E/AndroidRuntime( 3635): at android.os.Handler.dispatchMessage(Handler.java:102)
09-27 12:17:01.293 E/AndroidRuntime( 3635): at android.os.Looper.loop(Looper.java:154)
这在google的变更说明有 介绍https://developer.android.com/preview/behavior-changes.html#ndk,
具体是什么原因呢,怎么解决这种问题呢,google给出了一个官方的解决办法(如上链接),这里也给出另外一种方法。
首先,主要原因是google在N上对.so库的加载进行了限制,限制了so库指从部分指定的路径进行加载,不在这个路径的so提示
java.lang.UnsatisfiedLinkError: dlopen failed: library “xxx.so” not found 或
java.lang.UnsatisfiedLinkError: dlopen failed: library “/vendor/lib64/xxx.so” needed or dlopened by “/system/lib64/libnativeloader.so” is not accessible for the namespace “classloader-namespace” 或 其他异常错误提示。
N上对so库加载的搜索路径方式为ld_library_path, runtime path, permit path,不在这个搜索路径下则加载失败。
从代码层面看,主要是类加载器ClassLoader的相关处理,
code1: (loadedApk.java getClassLoader()) check sdk version
// DO NOT SHIP: this is a workaround for apps loading native libraries
// provided by 3rd party apps using absolute path instead of corresponding
// classloader; see http://b/26954419 for example.
if (mApplicationInfo.targetSdkVersion <= 23) {
libraryPermittedPath += File.pathSeparator + “/data/app”;
}
Code2: (loadedApk.java getClassLoader()) N add a new PermittedPath
String libraryPermittedPath = mDataDir;
Code3: (native_loader.cpp) use the new namespace rule with search path: ld_library_path, runtime path, permit path.
在明白原因之后,
解决办法则是将自己的so加入到允许路径的白名单里面,具体操作为,如果不改代码实现,则导出设备的/vendor/etc/public.libraries.txt 或/etc/public.libraries.txt文件,将so名字添加进去,在push到设备,重启即可。
Android N 版本有个新feature,就是普通应用不能直接引用系统的一些so库了,只能直接引用public.libraries.txt文件中过滤的so库。这个网址有介绍怎么处理。
source.android.com/devices/tec…
具体情况是这样的:我有一个系统权限的apk,这个apk会编译出一些so库放在system/lib目录下面,刚刷机这个apk是可以引用到这些so库的,但我调试的时候直接install这个apk,运行的时候居然直接挂了!!我也是醉了。没想到这个新feature居然影响到我的系统权限的apk。真蛋疼,我可不想每次push这个apk然后重启才生效,一般我都是直接install的,但现在好日子貌似到头了。
一.看看报错信息罗
具体报错的信息如下:
needed or dlopened by
"/system/lib64/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
大概的意思就是应用nativeloader打不开libhaha_utils.so这个so库了,就崩溃了!!好残忍。libhaha_utils.so这个库是用我用Android.mk编译后放在system/lib64下面的。但现在打不开了。
为啥呢?
因为/system/lib64/不在APK查找so库的合法路径啊,合法路径有啥呢?
上面log就有说明啦。下面三个路径都没有找到libhaha_utils.so库,所以就挂了。
ld_library_paths="",
default_library_paths="/system/fake-libs64:/data/app/com.example.haha-1/base.apk!/lib/arm64-v8a", permitted_paths="/data:/mnt/expand:/data/data/com.example.haha
二.那为啥刚刷机时APK可以用,Install这个apk后就不能用了呢?
这个apk可是系统权限的哟,就是apk的清单AndroidManifest中有下面一句
android:sharedUserId="android.uid.system"
正常来说,这种高端apk的permitted_paths是包含system/lib64的,从源码可以知道
/frameworks/base/ core/java/android/app/LoadedApk.java
1 //如果是系统apk并且没有升级过
2 final boolean isBundledApp = mApplicationInfo.isSystemApp()
3 && !mApplicationInfo.isUpdatedSystemApp();
5 String libraryPermittedPath = mDataDir;
6 if (isBundledApp) { //permitted_paths就增加system/lib64
7 // This is necessary to grant bundled apps access to
8 // libraries located in subdirectories of /system/lib
9 libraryPermittedPath += File.pathSeparator +
10 System.getProperty("java.library.path");
11 }
看上面的注释就知道啦,如果是系统apk并且没有升级过的话,so库的搜索路径就会增加一个system/lib64。我去,google搞啥呢,为什么还要限定不能升级。
因为install -r来安装apk就相当于升级,所以刷机时apk可以用,install升级后不能用。
三.那如何解决这个鬼问题呢?
我纯粹是为了调试方便,所以参考google的链接
source.android.com/devices/tec…
google.png
应用可以调用/vendor/etc/public.libraries.txt和/system/etc/public.libraries.txt里面的所有so库,所以哥往这个文件写入libhaha_utils.so,这个库就变成共用的了,任意应用就可以找到这个so库了,终于可以欢快地使用install apk的方式调试啦!!再也不用重启了!!
下面是原生google的图
Paste_Image.png
大概有这么些个so库是共用的。
libandroid.so
libc.so
libdl.so
libEGL.so
libGLESv1_CM.so
......
可以看看原生的这笔提交修改的。
android-review.googlesource.com/#/c/209029/
四.看看源码这个public.libraries.txt文件是咋玩的
在这个源码里面用到这个txt文件
/system/core/libnativeloader/native_loader.cpp
在LibraryNamespaces类的Initialize()会读取这个文件,将so库设置为公共so库,所谓公共so库,就是这个so库谁都能用啦。
1 static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
2 static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
3 void Initialize() {
4 ..................
5 std::vector<std::string> sonames;
6 ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
7 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
8 public_libraries_ = base::Join(sonames, ':');
9 .............
10 }
这个方法时什么时候调用的呢?大概过下流程罗。
首先在创建一个虚拟机的时候,初始化NativeLoader,这个NativeLoader,顾名思义,就是用来装载so库的。
/art/runtime/ java_vm_ext.cc
1 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
2 ................
3 // Initialize native loader. This step makes sure we have
4 // everything set up before we start using JNI.
5 android::InitializeNativeLoader();
6 ..............
然后进入native_loader,进行初始化
/system/core/libnativeloader/native_loader.cpp
1 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
3 void InitializeNativeLoader() {
4 g_namespaces->Initialize();
初始化是调用LibraryNamespaces类的Initialize完成公共so库的赋值,哈哈哈,搞定!!
1 void Initialize() {
2 ..................
3 std::vector<std::string> sonames;
4 ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
5 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
6 public_libraries_ = base::Join(sonames, ':');
7 .............
8 }
总结:
1.Android N 不能直接调用系统的一些私有库了,公用的库都定义在public.libraries.txt里面。
2.系统应用刚刷机是能够调用system/lib64下的库,但通过install升级该应用时,应用打开会挂。因为升级后permitted_paths就不再包含system/lib64了。所以我们可以将apk要用到的库名称写到public.libraries.txt中去解决快速调试问题。
android N : UnsatisfiedLinkError 只能访问设置为公用库的so库 在android N上使用 .so作为apk的第三方库的时候,会发生[添加链接描述](https://blog.csdn.net/weixin_42082222/article/details/104650503)java.lang.UnsatisfiedLinkError: 09-27 12:17...
load
Library msc error:java.lang.
UnsatisfiedLinkError: dalvik.system.PathClass
Loader[DexPathList[[zip file “/data/app/com.example.xflinean-1/base.apk”],
nativeLibraryDirectories=[/vendor/
lib, /system/
lib]]] couldn’t find “
libmsc.so”
出现加载so包有问题时
在buidl.gradle(module:app)下的
android{
defaultConfig {
在CentOS7上安装KETTLE8的时候用到的,解决了以下问题
org.eclipse.swt.SWTError: No more handles [MOZILLA_FIVE_HOME=''] (java.lang.UnsatisfiedLinkError: Could not load SWT library. Reasons:
no swt-mozilla-gtk-4335 in java.library.path
no swt-mozilla-gtk in java.library.path
/root/.swt/lib/linux/x86_64/libswt-mozilla-gtk-4335.so: libxpcom.so: cannot open shared object file: No such file or directory
Can't load library: /root/.swt/lib/linux/x86_64/libswt-mozilla-gtk.so
下载后解压出tar文件 上传到linux运行以下命令
# tar -xvf xulrunner*.tar
# cd ./xulrunner
# ./xulrunner -register-global
Android系统中,system.load,system.load
Library和dlopen是三个可以加载共享
库的方式。其中,system.load,system.load
Library是在Java代码中被使用的,dlopen是在cpp代码中被使用的。
system.load
system.load接收一个路径参数,该参数
libcore/ojluni/src/main/java/java/lang/System.java
@CallerSensitive
public s
Android 加载so库:dlopen failed: library “/system/lib/libSpiDevice.so” needed or dlopened by “/system/lib/libnativeloader.so” is not accessible for the namespace “classloader-namespace”
简易说明我的解决方法,不代表一定可以...
library "/system/lib64/libxxxx.so" ("/system/lib/libxxxxx.so") needed or dlopened by"/system/lib64/libnativeloader.so" is not accessible for the namespace "classloader-namespace"
修改system/core/rootdir/et
System : java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib64/libxxx.so"
needed or dlopened by "/system/lib64/libnativeloader.so" is not accessible for the namespace "classloader-namespace"
E/linker: library "/vendor/lib64/libgnustl_shared.so" ("/vendor/lib64/libgnustl_shared.so") needed or dlopened by "/apex/com.android.runtime/lib64/libnativeloader.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths="", default_library_paths="/data/app/edu.njucm.sportsapp-IdmLdNNAvItyHArn-3btmg==/lib/arm64:/data/app/edu.njucm.sportsapp-IdmLdNNAvItyHArn-3btmg==/base.apk!/lib/arm64-v8a", permitted_paths="/data:/mnt/expand:/data/data/edu.njucm.sportsapp"] 2023-05-11 22:00:21.758 27788-27788/edu.njucm.sportsapp W/System.err: java.lang.UnsatisfiedLinkError: dlopen failed: library "/vendor/lib64/libgnustl_shared.so" needed or dlopened by "/apex/com.android.runtime/lib64/libnativeloader.so" is not accessible for the namespace "classloader-namespace" 2023-05-11 22:00:21.758 27788-27788/edu.njucm.sportsapp W/System.err: at java.lang.Runtime.loadLibrary0(Runtime.java:1071)
AIDL使用接口回调中出现beginBroadcast() called while already in a broadcast的错误
sexy_99:
Unity3D应用--打造Android车载3D车模桌面(车载主界面开发)
沈阳_王东一: