Android6.0 不同方式安装apk copy lib流程

一、安装lib库

安装lib库代码,主要代码都在scanPackageDirtyLI函数中,先是调用了derivePackageAbi,这个函数中就把lib库的路径创建好了,也把lib库copy到这个目录下,然后后面会调用Installd的方法,在data/data/apk相关目录 下的lib 创建软链接到真正放lib的地方。

  1. if ((scanFlags & SCAN_NEW_INSTALL) == 0) {  
  2.     derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);  
  3.   
  4.     // Some system apps still use directory structure for native libraries  
  5.     // in which case we might end up not detecting abi solely based on apk  
  6.     // structure. Try to detect abi based on directory structure.  
  7.     if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&  
  8.             pkg.applicationInfo.primaryCpuAbi == null) {  
  9.         setBundledAppAbisAndRoots(pkg, pkgSetting);  
  10.         setNativeLibraryPaths(pkg);  
  11.     }  
  12.   
  13. else {  
  14.     if ((scanFlags & SCAN_MOVE) != 0) {  
  15.         // We haven't run dex-opt for this move (since we've moved the compiled output too)  
  16.         // but we already have this packages package info in the PackageSetting. We just  
  17.         // use that and derive the native library path based on the new codepath.  
  18.         pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString;  
  19.         pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString;  
  20.     }  
  21.   
  22.     // Set native library paths again. For moves, the path will be updated based on the  
  23.     // ABIs we've determined above. For non-moves, the path will be updated based on the  
  24.     // ABIs we determined during compilation, but the path will depend on the final  
  25.     // package path (after the rename away from the stage path).  
  26.     setNativeLibraryPaths(pkg);  
  27. }  
  28.   
  29. if (true) Slog.i(TAG, "Linking native library dir for " + path);  
  30. final int[] userIds = sUserManager.getUserIds();  
  31. synchronized (mInstallLock) {  
  32.     // Make sure all user data directories are ready to roll; we're okay  
  33.     // if they already exist  
  34.     if (!TextUtils.isEmpty(pkg.volumeUuid)) {  
  35.         for (int userId : userIds) {  
  36.             if (userId != 0) {  
  37.                 mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,  
  38.                         UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,  
  39.                         pkg.applicationInfo.seinfo);  
  40.             }  
  41.         }  
  42.     }  
  43.   
  44.     // Create a native library symlink only if we have native libraries  
  45.     // and if the native libraries are 32 bit libraries. We do not provide  
  46.     // this symlink for 64 bit libraries.  
  47.     if (pkg.applicationInfo.primaryCpuAbi != null &&  
  48.             !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {  
  49.         final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;  
  50.         for (int userId : userIds) {  
  51.             if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,  
  52.                     nativeLibPath, userId) < 0) {  
  53.                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,  
  54.                         "Failed linking native library dir (user=" + userId + ")");  
  55.             }  
  56.         }  
  57.     }  
  58. }  


二、 确定lib目录

那我们先从最核心的derivePackageAbi函数开始分析,derivePackageAbi这个函数一开始就调用了setNativeLibraryPaths,因此我们还是先看下这个函数:

  1. private void setNativeLibraryPaths(PackageParser.Package pkg) {  
  2.     final ApplicationInfo info = pkg.applicationInfo;  
  3.     final String codePath = pkg.codePath;  
  4.     final File codeFile = new File(codePath);  
  5.     final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();  
  6.     final boolean asecApp = info.isForwardLocked() || info.isExternalAsec();  
  7.   
  8.     info.nativeLibraryRootDir = null;  
  9.     info.nativeLibraryRootRequiresIsa = false;  
  10.     info.nativeLibraryDir = null;  
  11.     info.secondaryNativeLibraryDir = null;  
  12.   
  13.     if (isApkFile(codeFile)) {//是apk还是目录  
  14.         // Monolithic install  
  15.         if (bundledApp) {//系统应用相关  
  16.             // If "/system/lib64/apkname" exists, assume that is the per-package  
  17.             // native library directory to use; otherwise use "/system/lib/apkname".  
  18.             final String apkRoot = calculateBundledApkRoot(info.sourceDir);  
  19.             final boolean is64Bit = VMRuntime.is64BitInstructionSet(  
  20.                     getPrimaryInstructionSet(info));  
  21.   
  22.             // This is a bundled system app so choose the path based on the ABI.  
  23.             // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this  
  24.             // is just the default path.  
  25.             final String apkName = deriveCodePathName(codePath);  
  26.             final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME;  
  27.             info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir,  
  28.                     apkName).getAbsolutePath();  
  29.   
  30.             if (info.secondaryCpuAbi != null) {  
  31.                 final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME;  
  32.                 info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot),  
  33.                         secondaryLibDir, apkName).getAbsolutePath();  
  34.             }  
  35.         } else if (asecApp) {  
  36.             info.nativeLibraryRootDir = new File(codeFile.getParentFile(), LIB_DIR_NAME)  
  37.                     .getAbsolutePath();  
  38.         } else {  
  39.             final String apkName = deriveCodePathName(codePath);  
  40.             info.nativeLibraryRootDir = new File(mAppLib32InstallDir, apkName)//在data/app-lib下建一个apk的目录  
  41.                     .getAbsolutePath();  
  42.         }  
  43.   
  44.         info.nativeLibraryRootRequiresIsa = false;  
  45.         info.nativeLibraryDir = info.nativeLibraryRootDir;  
  46.     } else {//如果是目录  
  47.         // Cluster install  
  48.         info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath();//目录下直接建一个lib目录  
  49.         info.nativeLibraryRootRequiresIsa = true;  
  50.   
  51.         info.nativeLibraryDir = new File(info.nativeLibraryRootDir,  
  52.                 getPrimaryInstructionSet(info)).getAbsolutePath();  
  53.   
  54.         if (info.secondaryCpuAbi != null) {  
  55.             info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir,  
  56.                     VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath();  
  57.         }  
  58.     }  
  59. }  

上面这个函数就是看lib库最终的目录,我们先看逻辑,先来看文件是否是apk,如果不是apk是目录的话,直接在当前目录建一个lib目录。如果是普通应用就在data/app-lib下建一个apk目录。如果是系统应用会调用calculateBundledApkRoot函数来确定目录,最终会在system/lib vendor/lib oem/lib下建立相关目录。

calculateBundledApkRoot函数就是看apk是在system目录最终返回system目录,oem或者vendor目录最后返回oem或者vendor目录。

  1. private static String calculateBundledApkRoot(final String codePathString) {  
  2.     final File codePath = new File(codePathString);  
  3.     final File codeRoot;  
  4.     if (FileUtils.contains(Environment.getRootDirectory(), codePath)) {  
  5.         codeRoot = Environment.getRootDirectory();  
  6.     } else if (FileUtils.contains(Environment.getOemDirectory(), codePath)) {  
  7.         codeRoot = Environment.getOemDirectory();  
  8.     } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {  
  9.         codeRoot = Environment.getVendorDirectory();  
  10.     } else {  
  11.         // Unrecognized code path; take its top real segment as the apk root:  
  12.         // e.g. /something/app/blah.apk => /something  
  13.         try {  
  14.             File f = codePath.getCanonicalFile();  
  15.             File parent = f.getParentFile();    // non-null because codePath is a file  
  16.             File tmp;  
  17.             while ((tmp = parent.getParentFile()) != null) {  
  18.                 f = parent;  
  19.                 parent = tmp;  
  20.             }  
  21.             codeRoot = f;  
  22.             Slog.w(TAG, "Unrecognized code path "  
  23.                     + codePath + " - using " + codeRoot);  
  24.         } catch (IOException e) {  
  25.             // Can't canonicalize the code path -- shenanigans?  
  26.             Slog.w(TAG, "Can't canonicalize code path " + codePath);  
  27.             return Environment.getRootDirectory().getPath();  
  28.         }  
  29.     }  
  30.     return codeRoot.getPath();  
  31. }  


三、从apk中copy lib库

然后我们来看derivePackageAbi函数,我们先调用了setNativeLibraryPaths来确定了lib库的目录,然后NativeLibraryHelper.Handle.create来打开lapk中文件,接着又调用NativeLibraryHelper.copyNativeBinariesForSupportedAbi把apk的lib库文件copy到创建的lib目录。

  1. public void derivePackageAbi(PackageParser.Package pkg, File scanFile,  
  2.                              String cpuAbiOverride, boolean extractLibs)  
  3.         throws PackageManagerException {  
  4.     setNativeLibraryPaths(pkg);  
  5.   
  6.     if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() ||  
  7.             (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) {  
  8.         extractLibs = false;  
  9.     }  
  10.   
  11.     final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;  
  12.     final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;  
  13.   
  14.     NativeLibraryHelper.Handle handle = null;  
  15.     try {  
  16.         handle = NativeLibraryHelper.Handle.create(scanFile);  
  17.         final File nativeLibraryRoot = new File(nativeLibraryRootStr);  
  18.   
  19.         // Null out the abis so that they can be recalculated.  
  20.         pkg.applicationInfo.primaryCpuAbi = null;  
  21.         pkg.applicationInfo.secondaryCpuAbi = null;  
  22.         if (isMultiArch(pkg.applicationInfo)) {  
  23.             // Warn if we've set an abiOverride for multi-lib packages..  
  24.             // By definition, we need to copy both 32 and 64 bit libraries for  
  25.             // such packages.  
  26.             if (pkg.cpuAbiOverride != null  
  27.                     && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) {  
  28.                 Slog.w(TAG, "Ignoring abiOverride for multi arch application.");  
  29.             }  
  30.   
  31.             int abi32 = PackageManager.NO_NATIVE_LIBRARIES;  
  32.             int abi64 = PackageManager.NO_NATIVE_LIBRARIES;  
  33.             if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {  
  34.                 if (extractLibs) {  
  35.                     abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,  
  36.                             nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,  
  37.                             useIsaSpecificSubdirs);  
  38.                 } else {  
  39.                     abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);  
  40.                 }  
  41.             }  
  42.   
  43.             maybeThrowExceptionForMultiArchCopy(  
  44.                     "Error unpackaging 32 bit native libs for multiarch app.", abi32);  
  45.   
  46.             if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {  
  47.                 if (extractLibs) {  
  48.                     abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,  
  49.                             nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,  
  50.                             useIsaSpecificSubdirs);  
  51.                 } else {  
  52.                     abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);  
  53.                 }  
  54.             }  
  55.   
  56.             maybeThrowExceptionForMultiArchCopy(  
  57.                     "Error unpackaging 64 bit native libs for multiarch app.", abi64);  
  58.   
  59.             if (abi64 >= 0) {  
  60.                 pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];  
  61.             }  
  62.   
  63.             if (abi32 >= 0) {  
  64.                 final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];  
  65.                 if (abi64 >= 0) {  
  66.                     pkg.applicationInfo.secondaryCpuAbi = abi;  
  67.                 } else {  
  68.                     pkg.applicationInfo.primaryCpuAbi = abi;  
  69.                 }  
  70.             }  
  71.         } else {  
  72.             String[] abiList = (cpuAbiOverride != null) ?  
  73.                     new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;  
  74.   
  75.             // Enable gross and lame hacks for apps that are built with old  
  76.             // SDK tools. We must scan their APKs for renderscript bitcode and  
  77.             // not launch them if it's present. Don't bother checking on devices  
  78.             // that don't have 64 bit support.  
  79.             boolean needsRenderScriptOverride = false;  
  80.             if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&  
  81.                     NativeLibraryHelper.hasRenderscriptBitcode(handle)) {  
  82.                 abiList = Build.SUPPORTED_32_BIT_ABIS;  
  83.                 needsRenderScriptOverride = true;  
  84.             }  
  85.             final int copyRet;  
  86.             if (extractLibs) {  
  87.                 copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,  
  88.                         nativeLibraryRoot, abiList, useIsaSpecificSubdirs);  
  89.             } else {  
  90.                 copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);  
  91.             }  
  92.   
  93.             if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {  
  94.                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,  
  95.                         "Error unpackaging native libs for app, errorCode=" + copyRet);  
  96.             }  
  97.   
  98.             if (copyRet >= 0) {  
  99.                 pkg.applicationInfo.primaryCpuAbi = abiList[copyRet];  
  100.             } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) {  
  101.                 pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride;  
  102.             } else if (needsRenderScriptOverride) {  
  103.                 pkg.applicationInfo.primaryCpuAbi = abiList[0];  
  104.             }  
  105.         }  
  106.     } catch (IOException ioe) {  
  107.         Slog.e(TAG, "Unable to get canonical file " + ioe.toString());  
  108.     } finally {  
  109.         IoUtils.closeQuietly(handle);  
  110.     }  
  111.   
  112.     // Now that we've calculated the ABIs and determined if it's an internal app,  
  113.     // we will go ahead and populate the nativeLibraryPath.  
  114.     setNativeLibraryPaths(pkg);  
  115. }  

然后我们再回到scanPackageDirtyLI函数,下面会调用Installd的linkNativeLibraryDirectory函数来创建lib库的软链接

  1. if (pkg.applicationInfo.primaryCpuAbi != null &&  
  2.         !VMRuntime.is64BitAbi(pkg.applicationInfo.primaryCpuAbi)) {  
  3.     final String nativeLibPath = pkg.applicationInfo.nativeLibraryDir;  
  4.     for (int userId : userIds) {  
  5.         if (mInstaller.linkNativeLibraryDirectory(pkg.volumeUuid, pkg.packageName,  
  6.                 nativeLibPath, userId) < 0) {  
  7.             throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,  
  8.                     "Failed linking native library dir (user=" + userId + ")");  
  9.         }  
  10.     }  
  11. }  


四、创建lib软链接

最后在installd中调用如下代码,最后调用symlink来创建软链接。

  1. int linklib(const charuuidconst char* pkgname, const char* asecLibDir, int userId)  
  2. {  
  3.     struct stat s, libStat;  
  4.     int rc = 0;  
  5.   
  6.     std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));  
  7.     std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);  
  8.   
  9.     const char* pkgdir = _pkgdir.c_str();  
  10.     const char* libsymlink = _libsymlink.c_str();  
  11.   
  12.     if (stat(pkgdir, &s) < 0) return -1;  
  13.   
  14.     if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {  
  15.         ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));  
  16.         return -1;  
  17.     }  
  18.   
  19.     if (chmod(pkgdir, 0700) < 0) {  
  20.         ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));  
  21.         rc = -1;  
  22.         goto out;  
  23.     }  
  24.   
  25.     if (lstat(libsymlink, &libStat) < 0) {  
  26.         if (errno != ENOENT) {  
  27.             ALOGE("couldn't stat lib dir: %s\n", strerror(errno));  
  28.             rc = -1;  
  29.             goto out;  
  30.         }  
  31.     } else {  
  32.         if (S_ISDIR(libStat.st_mode)) {  
  33.             if (delete_dir_contents(libsymlink, 1, NULL) < 0) {  
  34.                 rc = -1;  
  35.                 goto out;  
  36.             }  
  37.         } else if (S_ISLNK(libStat.st_mode)) {  
  38.             if (unlink(libsymlink) < 0) {  
  39.                 ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));  
  40.                 rc = -1;  
  41.                 goto out;  
  42.             }  
  43.         }  
  44.     }  
  45.   
  46.     if (symlink(asecLibDir, libsymlink) < 0) {  
  47.         ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,  
  48.                 strerror(errno));  
  49.         rc = -errno;  
  50.         goto out;  
  51.     }  
  52.   
  53. out:  
  54.     if (chmod(pkgdir, s.st_mode) < 0) {  
  55.         ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));  
  56.         rc = -errno;  
  57.     }  
  58.   
  59.     if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {  
  60.         ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));  
  61.         return -errno;  
  62.     }  
  63.   
  64.     return rc;  
  65. }  


五、实例

这节主要看下具体apk的安装目录

5.1 普通应用

5.1.1 没有目录

没有目录的且是普通apk的lib安装位置

  1. root@lc1861evb_arm64:/data/app-lib # ls  
  2. IflytekInput  
  3. MOffice  
  4. NotePadPlus  

再来看data/data下面的讯飞目录,lib目录直接是软链接到/data/app_lib/IflytekInput

  1. drwxrwx--x u0_a61   u0_a61            2016-09-21 22:16 cache  
  2. drwxrwx--x u0_a61   u0_a61            2016-09-21 22:16 code_cache  
  3. drwxrwx--x u0_a61   u0_a61            2016-09-21 22:16 databases  
  4. drwxrwx--x u0_a61   u0_a61            2016-09-21 22:16 files  
  5. lrwxrwxrwx root     root              2016-09-21 22:47 lib -> /data/app-lib/IflytekInput  
  6. drwx------ u0_a61   u0_a61            2016-09-21 22:47 shared_prefs  

5.1.2 有目录


而如果我们把讯飞输入法放在data/app/IflytekInput目录下,就会把lib文件放在该目录下

  1. root@lte26007:/data/app/IflytekInput # ls  
  2. IflytekInput.apk  
  3. lib  

当然软链接也会到/data/app/IflytekInput/lib/arm目录

  1. root@lte26007:/data/data/com.iflytek.inputmethod # ls -l  
  2. drwxrwx--x u0_a62   u0_a62            1980-01-08 07:12 cache  
  3. drwxrwx--x u0_a62   u0_a62            1980-01-08 07:12 code_cache  
  4. drwxrwx--x u0_a62   u0_a62            1980-01-08 07:12 databases  
  5. drwxrwx--x u0_a62   u0_a62            1980-01-08 07:12 files  
  6. lrwxrwxrwx root     root              1980-01-08 07:11 lib -> /data/app/IflytekInput/lib/arm  
  7. drwx------ u0_a62   u0_a62            1980-01-08 07:12 shared_prefs  


5.2 系统应用

系统应用很奇怪,在扫描时无论是有目录还是没有目录,最后都没有生成lib目录,也没有copylib库(在手机上面busybox find相关库也没有找到),但是data/data相关app下面有lib的软链接,但是打开错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值