Android找不到so,现实上apk中有的

打印 上一主题 下一主题

主题 949|帖子 949|积分 2847

办理apk中有.so,现实运行时找不到的问题
排查方向:


  • ①、.so安装位置是否现实存在文件(context.getApplicationInfo().nativeLibraryDir)
  • ②、当前ARM架构适配配置或者匹配(armeabi-v7a, arm64-v8a, x86_64, ...)
  • ③、加载方式是否正确[System.loadLibrary("so_name_but_no_'lib'_prefix")/System.load("so_absolute_path")]
  • ④、Android版本(Android 31+),AGP版本(AGP 4.2.0+)参考下方配置 ↓↓↓
  • ⑤、android:extractNativeLibs=true是否配置(或者DSL选项useLegacyPackaging=true)
  • ⑥、库文件没有访问权限

  • Android .so存储位置
    可以通过如下方式获取so文件的加载位置
  1. String so_path = context.getApplicationInfo().nativeLibraryDir; //查看加载 .so 的位置
复制代码
举个栗子
体系应用:/system/lib/xxx[/vendor/lib (三方OEM厂商)] 或者 system/app/xxx/lib



三方应用: data/app/[package-name]/lib
注意:package-name大概会是一串随机数字,可以通过如下adb命令行根据包名查看app的安装位置:
  1. adb shell
  2. pm list package -f |grep com.axxxx
复制代码

您可以通过如下代码查找.so文件所在的目次,参考自:
   https://blog.csdn.net/wangbaochu/article/details/47805921
  1.     /**
  2.      * The function use to find so path for compatible android system
  3.      * Android OS >= 2.3
  4.      */
  5.     public static String findLibrary1(Context context, String libName) {
  6.         String result = null;
  7.         ClassLoader classLoader = (context.getClassLoader());
  8.         if (classLoader != null) {
  9.             try {
  10.                 Method findLibraryMethod = classLoader.getClass().getMethod("findLibrary", new Class<?>[] { String.class });   
  11.                 if (findLibraryMethod != null) {
  12.                     Object objPath = findLibraryMethod.invoke(classLoader, new Object[] { libName });
  13.                     if (objPath != null && objPath instanceof String) {
  14.                         result = (String) objPath;
  15.                     }
  16.                 }
  17.             } catch (NoSuchMethodException e) {
  18.                 Log.e("findLibrary1", e.toString());
  19.             } catch (IllegalAccessException e) {
  20.                 Log.e("findLibrary1", e.toString());
  21.             } catch (IllegalArgumentException e) {
  22.                 Log.e("findLibrary1", e.toString());
  23.             } catch (InvocationTargetException e) {
  24.                 Log.e("findLibrary1", e.toString());
  25.             } catch (Exception e) {
  26.                 Log.e("findLibrary1", e.toString());
  27.             }
  28.         }
  29.         return result;
  30.     }
  31.     /**
  32.      * The function use to find so path for compatible android system
  33.      * Android OS <= 2.2
  34.      */
  35.     public static String findLibrary2(Context context, String libName) {
  36.         String result = null;
  37.         ClassLoader classLoader = (context.getClassLoader());
  38.         if (classLoader != null) {
  39.             try {
  40.                 Method findLibraryMethod = classLoader.getClass().getDeclaredMethod("findLibrary", new Class<?>[] { String.class });
  41.                 if (findLibraryMethod != null) {
  42.                     if (!findLibraryMethod.isAccessible()) {
  43.                         findLibraryMethod.setAccessible(true);
  44.                     }
  45.                     Object objPath = findLibraryMethod.invoke(classLoader, new Object[] { libName });
  46.                     if (objPath != null && objPath instanceof String) {
  47.                         result = (String) objPath;
  48.                     }
  49.                 }
  50.             } catch (NoSuchMethodException e) {
  51.                 Log.e("findLibrary2", e.toString());
  52.             } catch (IllegalAccessException e) {
  53.                 Log.e("findLibrary2", e.toString());
  54.             } catch (IllegalArgumentException e) {
  55.                 Log.e("findLibrary2", e.toString());
  56.             } catch (InvocationTargetException e) {
  57.                 Log.e("findLibrary2", e.toString());
  58.             } catch (Exception e) {
  59.                 Log.e("findLibrary2", e.toString());
  60.             }
  61.         }
  62.         return result;
  63.     }
复制代码

  • 查看Android打包配置是否指定了对应ARM架构
  1. android {
  2.     // ...
  3.     defaultConfig {
  4.         // ...
  5.         ndk {
  6.             // 目前Android支持的ABIs
  7.             abiFilters 'mips', 'mips64', 'x86', 'x86–64', 'arm64-v8a', 'armeabi', 'armeabi-v7a'
  8.         }
  9.     }
  10. }
复制代码
您可以通过如下代码获取当前设备支持的ABIs:
  1.         /**
  2.      * An ordered list of ABIs supported by this device
  3.      *
  4.      * @return ABI
  5.      */
  6.     public String[] getABIs() {
  7.         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  8.             return Build.SUPPORTED_ABIS;
  9.         } else {
  10.             return new String[]{Build.CPU_ABI, Build.CPU_ABI2};
  11.         }
  12.     }
复制代码
或者如下adb命令获取:

关于ABI架构引用如下文章:
   https://www.jianshu.com/p/68b52659a5f6
  1.在android4.4以下版本的安装过程中的,是先把所有so库全部寻找出来,然后优先列出cpu类型(通过ro.product.cpu.abi属性获得)目次下的so库,如果有其他的cpu类型下有跟手机cpu类型名称不同等的so库,则会将兼容cpu架构(通过ro.product.cpu.abi2属性获得)的别的的库也列出来。将列出来so库全部拷贝的体系指定目次,以供运行时加载。 即在android4.4以下版本,一个so库只要在 ro.product.cpu.abi和ro.product.cpu.abi2属性目次下至少存在一个就可以了。在android4.4以下的arm架构的设备 ro.product.cpu.abi的属性通常是armeabi-v7a, ro.product.cpu.abi2的属性值是armeabi,而且armeabi-v7a设备一定兼容armeabi。但不清除某些设备的ro.product.cpu.abi的属性为armeabi。
2.在android5.0及以上,由于增加了arm64的支持,app安装时的so库拷贝代码也修改了。修改成只拷贝一个最符合的目次下的so库到体系指定目次。 在arm架构下,64位cpu的优先级是arm64-v8a > armeabi-v7a > armeabi,32位cpu的优先级是armeabi-v7a > armeabi ,优先级可通过ro.product.cpu.abilist属性查看。由于android5.0是拷贝团体目次,所以在每一个目次下的,都必须要有完备的so,即所有app需要so库都要有。例如64位的cpu的设备上,
如果app目次里存在arm64-v8a子目次,则只拷贝该目次下的so库,其他目次的so,纵然名称不一样,也不拷贝,如果arm64-v8a子目次的so库不全,则会报错。

  • so加载方式不对
    目前有两种加载方式(以某个平凡app下有个libtest.so文件为例):
    System.loadLibrary("so_name_but_no_'lib'_prefix") :会优先查找apk中的so目次,再查找体系目次,体系目次包括:/vendor/lib(64),/system/lib(64)
    System.load("so_absolute_path"): 直接加载制定路径下的so
  1. System.loadLibrary("test");// libtest.so
复制代码
  1. String soRoot = context.getApplicationInfo().nativeLibraryDir;
  2. System.load(soRoot + "/libtest.so");// libtest.so
复制代码

  • Google官方更新进行的调解和修改
   https://developer.android.google.cn/guide/topics/manifest/application-element?hl=zh-cn
  针对AGP >= 3.6.0需要在AndroidMainfest.xml清单文件中添加如下配置
  1. <application
  2.         android:extractNativeLibs="true"
  3.         ... >
  4. </application>   
复制代码
针对AGP >= 4.2.0需要在DSL中添加如下配置(上面配置过时)
  1. android {
  2.     packagingOptions {
  3.         jniLibs {
  4.             useLegacyPackaging true
  5.         }
  6.     }
  7. }
复制代码

  • 库文件没有访问权限
    .so文件有权限限制(文件读写权限/体系访问权限限制),不允许访问,可通过如下命令查看对应文件的访问权限:

关于权限分析参考如下:
   https://www.jianshu.com/p/ba0d31fc078a
  1. drwxr-xr-x:应该分解为四部分
  2. d rwx r-x r-x
  3. 第一部分:d表示目录文件,-表示普通文件,l表示链接文件,p表示管道。
  4. 第二部分:root用户拥有的权限
  5. 第三部分:用户组拥有的权限
  6. 第四部分:其他用户拥有的权限
  7. r表示可读,w表示可写,x表示可执行,r-x表示可读可执行不可写
  8. 查看文件权限方法:
  9. ls -lO (大写的o) + 所在文件夹路径
复制代码
举个栗子:
app需要引用体系的so库,当install情势的时间安装时,打开app需要使用/system/lib64目次下的so库时,提示不能访问。
原因分析:放到system/app下的app是可以找到的,但是平凡的安装情势的app是没有权限访问的,所以需要需要声明公有so库才能使用
  1. library "/system/lib64/libserialport.so" ("/system/lib64/libhqbindcs.so") needed or
  2. dlopened by"/system/lib64/libhqbindcs.so" is not accessible for the namespace
  3. "classloader-namespace"
复制代码
办理方法:
修改system/core/rootdir/etc/public.libraries.txt
添加你要使用的的so到此问题件中。
  1. cat public.libraries.txt
  2. ....
  3. libz.so
  4. libhqbindcs.so
复制代码
也可以直接不编译在板子上修改,对应目次/system/etc
   https://wkingdom.github.io/2020/04/04/JNI%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AEso%E6%8F%90%E7%A4%BAnot%20accessible/
https://www.jianshu.com/p/4be3d1dafbec

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表