安装APK时SO库的选择策略

本文详细介绍了Android系统从4.0以前到64位支持的不同版本中,安装APK时如何选择解压SO库的策略,包括可能出现的问题及配置SO的建议。在不同版本中,系统会选择主ABI或次ABI的SO库,存在拷贝不全或覆盖的现象。建议开发者根据设备兼容性和性能需求合理配置SO库。
摘要由CSDN通过智能技术生成

此文已由作者尹彬彬授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


0X0 前言

在Android系统中,当我们安装apk文件的时候,lib目录下的so文件会被解压到app的原生库目录,一般来说是放到/data/data/<package-name>/lib目录下,而根据系统和CPU架构的不同,其拷贝策略也是不一样的,在我们测试过程中发现不正确地配置了so文件,比如某些app使用第三方的so时,只配置了其中某一种CPU架构的so,可能会造成app在某些机型上的适配问题。所以这篇文章主要介绍一下在不同版本的Android系统中,安装apk时,PackageManagerService选择解压so库的策略,并给出一些so文件配置的建议。


0x1 Android4.0以前

当apk被安装时,执行路径虽然有差别,但最终要调用到的一个核心函数是copyApk,负责拷贝apk中的资源。

参考2.3.6的android源码,它的copyApk其内部函数一段选取原生库so逻辑:

 public static int listPackageNativeBinariesLI(ZipFile zipFile,
            List> nativeFiles) throws ZipException, IOException {
        String cpuAbi = Build.CPU_ABI;        int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles);        /*
         * Some architectures are capable of supporting several CPU ABIs
         * for example, 'armeabi-v7a' also supports 'armeabi' native code
         * this is indicated by the definition of the ro.product.cpu.abi2
         * system property.
         *
         * only scan the package twice in case of ABI mismatch
         */
        if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {            final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null);            if (cpuAbi2 != null) {
                result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles);
            }            if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
                Slog.w(TAG, "Native ABI mismatch from package file");                return PackageManager.INSTALL_FAILED_INVALID_APK;
            }            if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
                cpuAbi = cpuAbi2;
            }
        }        /*
         * Debuggable packages may have gdbserver embedded, so add it to
         * the list to the list of items to be extracted (as lib/gdbserver)
         * into the application's native library directory later.
         */
        if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
            listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles);
        }        return PackageManager.INSTALL_SUCCEEDED;
    }

这段代码中的Build.CPU_ABI和“ro.product.cpu.abi2”分别为手机支持的主abi和次abi属性字符串,abi为手机支持的指令集所代表的字符串,比如armeabi-v7a、armeabi、x86、mips等,而主abi和次abi分别表示手机支持的第一指令集和第二指令集。代码首先调用listPackageSharedLibsForAbiLI来遍历主abi目录。当主abi目录不存在时,才会接着调用listPackageSharedLibsForAbiLI遍历次abi目录。

/*
     * Find all files of the form lib//lib.so in the .apk
     * and add them to a list to be installed later.
     *
     * NOTE: this method may throw an IOException if the library cannot
     * be copied to its final destination, e.g. if there isn't enough
     * room left on the data partition, or a ZipException if the package
     * file is malformed.
     */
    private static int listPackageSharedLibsForAbiLI(ZipFile zipFile,
            String cpuAbi, List> libEntries) throws IOException,
            ZipException {        final int cpuAbiLen = cpuAbi.length();        boolean hasNativeLibraries = false;        boolean installedNativeLibraries = false;        if (DEBUG_NATIVE) {
            Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type "
                    + cpuAbi);
        }
        Enumeration entries = zipFile.entries();        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();            // skip directories
            if (entry.isDirectory()) {                continue;
            }
            String entryName = entry.getName();            /*
             * Check that the entry looks like lib//lib.so
             * here, but don't check the ABI just yet.
             *
             * - must be sufficiently long
             * - must end with LIB_SUFFIX, i.e. ".so"
             * - must start with APK_LIB, i.e. "lib/"
             */
            if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX)
                    || !entryName.startsWith(APK_LIB)) {                continue;
            }            // file name must start with LIB_PREFIX, i.e. "lib"
            int lastSlash = entryName.lastIndexOf('/');            if (lastSlash < 0
                    || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) {                continue;
            }
            hasNativeLibraries = true;            // check the cpuAbi now, between lib/ and /lib.so
            if (lastSlash != APK_LIB_LENGTH + cpuAbiLen
                    || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen))                continue;            /*
             * Extract the library file name, ensure 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值