PackageManagerService安装lib库
2017-09-02 14:18
375 查看
APP开发都会用到动态链路库,即so库。在代码中通常通过System.loadLibrary()来加载so库,但也经常会碰到App在一些手机上没有问题,在另外一些手机上使用时出错,如java.lang.UnsatisfiedLinkError,就是和动态链路库加载错误有关。想要解决这类问题,就要了解系统在安装APK的时候是如何处理so库的。下面从源码上分析这一过程。
在安装APK时,若APK包含lib库,PKMS也会相应的安装lib库。PKMS安装lib代码在扫描APK函数scanPackageDirtyLI()中。
安装lib库分为三部分:
1. 创建存放lib库目录
2. 解析APK文件,匹配ABI并拷贝对应ABI目录下的 lib文件到相应目录
3. 在data/data/apk相关目录 下的lib 创建软链接到真正放lib的地方
在scanPackageDirtyLI()扫描APK中,调用了derivePackageAbi()来安装lib库。
以上代码表示如果APK是新安装的,则会调用derivePackageAbi()来安装lib库。derivePackageAbi()如下:
derivePackageAbi()做了以下几件事:
1.调用setNativeLibraryPaths(pkg)创建lib目录
2. 如果需要提取lib库,即extractLibs为true,则调用NativeLibraryHelper.copyNativeBinariesForSupportedAbi()匹配ABI并拷贝对应 ABI目录下的 lib文件到相应目录
如果不需要lib库,则调用NativeLibraryHelper.findSupportedAbi()匹配ABI。
对于新安装的APK,都是需要提取lib库,即extractLibs为true。
3.设置APKprimaryCpuAbi、secondaryCpuAbi(APK设置了支持多核架构时设置)。
下面具体实现,创建lib目录方法setNativeLibraryPaths(pkg)如下:
若是系统内置APK,则在系统APK目录下创建lib目录,如system/lib、vendor/lib,若是用户自己安装的APK,则得data目录下创建lib目录,如data/app-lib下建apk目录。
创建完lib目录后,就是拷贝so库了。为了在不同的手机平台下能运行,开发这也会准备不同CPU架构下的so库。
在Eclipse或者Android Studio的project\app\src\main\jniLibs\经常可以看到下面这样的部分
同样不同的手机CPU架构不同,因此支持的ABI也不同,通过命令可以查看手机支持的abi
adb shell getprop ro.product.cpu.abilist,查看手机配置项。
如下是华为某手机所支持的ABI。
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
可以看出该手机支持的abi有 [arm64-v8a,armeabi-v7a,armeabi],若某APK仅提供了x86构架下的so库,则APK没法在该手机上运行。
手机支持的abi和apk提供的so库都不止一个,具体该如何匹配,即最后到底用了那个架构的so库呢。匹配原则在NativeLibraryHelper.copyNativeBinariesForSupportedAbi()中:
首先通过findSupportedAbi()找到匹配到的abi,然后根据abi,调用copyNativeBinaries()把对应abi下的so库靠别到指定的目录。
最终调用native方法nativeFindSupportedAbi()。
supportedAbis保存了系统支持的abi,系统abilist中是按优先级保存abi,即若apk中arm64-v8a的so库,findSupportedAbi 函数其实就是遍历 apk(其实就是一个压缩文件)中的所有文件,如果文件全路径中包含 abilist 中的某个 abi
字符串,则记录该 abi 字符串的索引,最终返回所有记录索引中最靠前的,即排在 abilist 中最前面的索引。
举个例子,假如我们的 app 中的 so 地址中有包含 arm64-v8a、armeabi-v7a 的字符串,同时 abilist 是 arm64-v8a,armeabi-v7a,armeab,那么这里就会返回 arm64-v8a。
确定好abi后,就是把对应abi下的so库靠别到指定的目录。调用方法copyNativeBinaries(),同样最终实现在native方法iterateOverNativeFiles()中
解压APK,根据确定的找到的CPUABI,只拷贝对应目录下的so库。
拷贝完so库后,就要设置primaryCpuAbi和secondaryCpuAbi,primaryCpuAbi 的值来决定我们的程序是运行在32位还是64位下的。
primaryCpuAbi和secondaryCpuAbi设置的逻辑在derivePackageAbi()中。
3.在data/data/apk相关目录 下的lib 创建软链接到真正放lib的地方
调用到了installd,最后调用symlink来创建软链接
可以查看手机目录
在安装APK时,若APK包含lib库,PKMS也会相应的安装lib库。PKMS安装lib代码在扫描APK函数scanPackageDirtyLI()中。
安装lib库分为三部分:
1. 创建存放lib库目录
2. 解析APK文件,匹配ABI并拷贝对应ABI目录下的 lib文件到相应目录
3. 在data/data/apk相关目录 下的lib 创建软链接到真正放lib的地方
在scanPackageDirtyLI()扫描APK中,调用了derivePackageAbi()来安装lib库。
if ((scanFlags & SCAN_NEW_INSTALL) == 0) { derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */); // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() && pkg.applicationInfo.primaryCpuAbi == nul 4000 l) { setBundledAppAbisAndRoots(pkg, pkgSetting); setNativeLibraryPaths(pkg); } } else { if ((scanFlags & SCAN_MOVE) != 0) { // We haven't run dex-opt for this move (since we've moved the compiled output too) // but we already have this packages package info in the PackageSetting. We just // use that and derive the native library path based on the new codepath. pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString; pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString; } // Set native library paths again. For moves, the path will be updated based on the // ABIs we've determined above. For non-moves, the path will be updated based on the // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). setNativeLibraryPaths(pkg); }
以上代码表示如果APK是新安装的,则会调用derivePackageAbi()来安装lib库。derivePackageAbi()如下:
private void derivePackageAbi(PackageParser.Package pkg, File scanFile, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException { // TODO: We can probably be smarter about this stuff. For installed apps, // we can calculate this information at install time once and for all. For // system apps, we can probably assume that this information doesn't change // after the first boot scan. As things stand, we do lots of unnecessary work. // Give ourselves some initial paths; we'll come back for another // pass once we've determined ABI below. setNativeLibraryPaths(pkg); // We would never need to extract libs for forward-locked and external packages, // since the container service will do it for us. We shouldn't attempt to // extract libs from system app when it was not updated. if (pkg.isForwardLocked() || pkg.applicationInfo.isExternalAsec() || (isSystemApp(pkg) && !pkg.isUpdatedSystemApp())) { extractLibs = false; } final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir; final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa; NativeLibraryHelper.Handle handle = null; try { handle = NativeLibraryHelper.Handle.create(pkg); // TODO(multiArch): This can be null for apps that didn't go through the // usual installation process. We can calculate it again, like we // do during install time. // // TODO(multiArch): Why do we need to rescan ASEC apps again ? It seems totally // unnecessary. final File nativeLibraryRoot = new File(nativeLibraryRootStr); // Null out the abis so that they can be recalculated. pkg.applicationInfo.primaryCpuAbi = null; pkg.applicationInfo.secondaryCpuAbi = null; if (isMultiArch(pkg.applicationInfo)) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (pkg.cpuAbiOverride != null && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } int abi32 = PackageManager.NO_NATIVE_LIBRARIES; int abi64 = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { if (extractLibs) { abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs); } else { abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); } } maybeThrowExceptionForMultiArchCopy( "Error unpackaging 32 bit native libs for multiarch app.", abi32); if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { if (extractLibs) { abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs); } else { abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); } } maybeThrowExceptionForMultiArchCopy( "Error unpackaging 64 bit native libs for multiarch app.", abi64); if (abi64 >= 0) { pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64]; } if (abi32 >= 0) { final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32]; if (abi64 >= 0) { if (pkg.use32bitAbi) { pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi; pkg.applicationInfo.primaryCpuAbi = abi; } else { pkg.applicationInfo.secondaryCpuAbi = abi; } } else { pkg.applicationInfo.primaryCpuAbi = abi; } } } else { String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; // Enable gross and lame hacks for apps that are built with old // SDK tools. We must scan their APKs for renderscript bitcode and // not launch them if it's present. Don't bother checking on devices // that don't have 64 bit support. boolean needsRenderScriptOverride = false; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; needsRenderScriptOverride = true; } final int copyRet; if (extractLibs) { copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs); } else { copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList); } if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Error unpackaging native libs for app, errorCode=" + copyRet); } if (copyRet >= 0) { pkg.applicationInfo.primaryCpuAbi = abiList[copyRet]; } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) { pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride; } else if (needsRenderScriptOverride) { pkg.applicationInfo.primaryCpuAbi = abiList[0]; } } } catch (IOException ioe) { Slog.e(TAG, "Unable to get canonical file " + ioe.toString()); } finally { IoUtils.closeQuietly(handle); } // Now that we've calculated the ABIs and determined if it's an internal app, // we will go ahead and populate the nativeLibraryPath. setNativeLibraryPaths(pkg); }
derivePackageAbi()做了以下几件事:
1.调用setNativeLibraryPaths(pkg)创建lib目录
2. 如果需要提取lib库,即extractLibs为true,则调用NativeLibraryHelper.copyNativeBinariesForSupportedAbi()匹配ABI并拷贝对应 ABI目录下的 lib文件到相应目录
如果不需要lib库,则调用NativeLibraryHelper.findSupportedAbi()匹配ABI。
对于新安装的APK,都是需要提取lib库,即extractLibs为true。
3.设置APKprimaryCpuAbi、secondaryCpuAbi(APK设置了支持多核架构时设置)。
下面具体实现,创建lib目录方法setNativeLibraryPaths(pkg)如下:
private void setNativeLibraryPaths(PackageParser.Package pkg) { final ApplicationInfo info = pkg.applicationInfo; final String codePath = pkg.codePath; final File codeFile = new File(codePath); final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp(); final boolean asecApp = info.isForwardLocked() || info.isExternalAsec(); info.nativeLibraryRootDir = null; info.nativeLibraryRootRequiresIsa = false; info.nativeLibraryDir = null; info.secondaryNativeLibraryDir = null; if (isApkFile(codeFile)) { // Monolithic install if (bundledApp) { // If "/system/lib64/apkname" exists, assume that is the per-package // native library directory to use; otherwise use "/system/lib/apkname". final String apkRoot = calculateBundledApkRoot(info.sourceDir); final boolean is64Bit = VMRuntime.is64BitInstructionSet( getPrimaryInstructionSet(info)); // This is a bundled system app so choose the path based on the ABI. // if it's a 64 bit abi, use lib64 otherwise use lib32. Note that this // is just the default path. final String apkName = deriveCodePathName(codePath); final String libDir = is64Bit ? LIB64_DIR_NAME : LIB_DIR_NAME; info.nativeLibraryRootDir = Environment.buildPath(new File(apkRoot), libDir, apkName).getAbsolutePath(); if (info.secondaryCpuAbi != null) { final String secondaryLibDir = is64Bit ? LIB_DIR_NAME : LIB64_DIR_NAME; info.secondaryNativeLibraryDir = Environment.buildPath(new File(apkRoot), secondaryLibDir, apkName).getAbsolutePath(); } } else if (asecApp) { info.nativeLibraryRootDir = new File(codeFile.getParentFile(), LIB_DIR_NAME) .getAbsolutePath(); } else { final String apkName = deriveCodePathName(codePath); info.nativeLibraryRootDir = new File(mAppLib32InstallDir, apkName) .getAbsolutePath(); } info.nativeLibraryRootRequiresIsa = false; info.nativeLibraryDir = info.nativeLibraryRootDir; } else { // Cluster install info.nativeLibraryRootDir = new File(codeFile, LIB_DIR_NAME).getAbsolutePath(); info.nativeLibraryRootRequiresIsa = true; info.nativeLibraryDir = new File(info.nativeLibraryRootDir, getPrimaryInstructionSet(info)).getAbsolutePath(); if (info.secondaryCpuAbi != null) { info.secondaryNativeLibraryDir = new File(info.nativeLibraryRootDir, VMRuntime.getInstructionSet(info.secondaryCpuAbi)).getAbsolutePath(); } } }
若是系统内置APK,则在系统APK目录下创建lib目录,如system/lib、vendor/lib,若是用户自己安装的APK,则得data目录下创建lib目录,如data/app-lib下建apk目录。
创建完lib目录后,就是拷贝so库了。为了在不同的手机平台下能运行,开发这也会准备不同CPU架构下的so库。
在Eclipse或者Android Studio的project\app\src\main\jniLibs\经常可以看到下面这样的部分
同样不同的手机CPU架构不同,因此支持的ABI也不同,通过命令可以查看手机支持的abi
adb shell getprop ro.product.cpu.abilist,查看手机配置项。
如下是华为某手机所支持的ABI。
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: [arm64-v8a]
[ro.product.cpu.abilist]: [arm64-v8a,armeabi-v7a,armeabi]
可以看出该手机支持的abi有 [arm64-v8a,armeabi-v7a,armeabi],若某APK仅提供了x86构架下的so库,则APK没法在该手机上运行。
手机支持的abi和apk提供的so库都不止一个,具体该如何匹配,即最后到底用了那个架构的so库呢。匹配原则在NativeLibraryHelper.copyNativeBinariesForSupportedAbi()中:
public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot, String[] abiList, boolean useIsaSubdir) throws IOException { createNativeLibrarySubdir(libraryRoot); /* * If this is an internal application or our nativeLibraryPath poin cafe ts to * the app-lib directory, unpack the libraries if necessary. */ int abi = findSupportedAbi(handle, abiList); if (abi >= 0) { /* * If we have a matching instruction set, construct a subdir under the native * library root that corresponds to this instruction set. */ final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]); final File subDir; if (useIsaSubdir) { final File isaSubdir = new File(libraryRoot, instructionSet); createNativeLibrarySubdir(isaSubdir); subDir = isaSubdir; } else { subDir = libraryRoot; } int copyRet = copyNativeBinaries(handle, subDir, abiList[abi]); if (copyRet != PackageManager.INSTALL_SUCCEEDED) { return copyRet; } } return abi; }
首先通过findSupportedAbi()找到匹配到的abi,然后根据abi,调用copyNativeBinaries()把对应abi下的so库靠别到指定的目录。
public static int findSupportedAbi(Handle handle, String[] supportedAbis) { int finalRes = NO_NATIVE_LIBRARIES; for (long apkHandle : handle.apkHandles) { final int res = nativeFindSupportedAbi(apkHandle, supportedAbis); if (res == NO_NATIVE_LIBRARIES) { // No native code, keep looking through all APKs. } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) { // Found some native code, but no ABI match; update our final // result if we haven't found other valid code. if (finalRes < 0) { finalRes = INSTALL_FAILED_NO_MATCHING_ABIS; } } else if (res >= 0) { // Found valid native code, track the best ABI match if (finalRes < 0 || res < finalRes) { finalRes = res; } } else { // Unexpected error; bail return res; } } return finalRes; }
最终调用native方法nativeFindSupportedAbi()。
static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray) { const int numAbis = env->GetArrayLength(supportedAbisArray); Vector<ScopedUtfChars*> supportedAbis; for (int i = 0; i < numAbis; ++i) { supportedAbis.add(new ScopedUtfChars(env, (jstring) env->GetObjectArrayElement(supportedAbisArray, i))); } ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle); if (zipFile == NULL) { return INSTALL_FAILED_INVALID_APK; } int status = NO_NATIVE_LIBRARIES; if (initApkScanLib() == LIB_INITED_AND_SUCCESS) { PFilterObject filter = GetFilterObjectFunc(zipFile->getFileDescriptor()); if (filter != NULL) { LibFileAbiDealer param; param.status = status; param.numAbis = numAbis; param.supportedAbis = &supportedAbis; int ret = FilterLibraryFunc(filter, dealLibAbiFile, ¶m); if ((0 == ret) || (1 == ret)) { status = param.status; for (int i = 0; i < numAbis; ++i) { delete supportedAbis[i]; } return status; } } } UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile)); if (it.get() == NULL) { return INSTALL_FAILED_INVALID_APK; } ZipEntryRO entry = NULL; while ((entry = it->next()) != NULL) { // We're currently in the lib/ directory of the APK, so it does have some native // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the // libraries match. if (status == NO_NATIVE_LIBRARIES) { status = INSTALL_FAILED_NO_MATCHING_ABIS; } const char* fileName = it->currentEntry(); const char* lastSlash = it->lastSlash(); // Check to see if this CPU ABI matches what we are looking for. const char* abiOffset = fileName + APK_LIB_LEN; const size_t abiSize = lastSlash - abiOffset; for (int i = 0; i < numAbis; i++) { const ScopedUtfChars* abi = supportedAbis[i]; if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) { // The entry that comes in first (i.e. with a lower index) has the higher priority. if (((i < status) && (status >= 0)) || (status < 0) ) { status = i; } } } } for (int i = 0; i < numAbis; ++i) { delete supportedAbis[i]; } return status; }
supportedAbis保存了系统支持的abi,系统abilist中是按优先级保存abi,即若apk中arm64-v8a的so库,findSupportedAbi 函数其实就是遍历 apk(其实就是一个压缩文件)中的所有文件,如果文件全路径中包含 abilist 中的某个 abi
字符串,则记录该 abi 字符串的索引,最终返回所有记录索引中最靠前的,即排在 abilist 中最前面的索引。
举个例子,假如我们的 app 中的 so 地址中有包含 arm64-v8a、armeabi-v7a 的字符串,同时 abilist 是 arm64-v8a,armeabi-v7a,armeab,那么这里就会返回 arm64-v8a。
确定好abi后,就是把对应abi下的so库靠别到指定的目录。调用方法copyNativeBinaries(),同样最终实现在native方法iterateOverNativeFiles()中
static install_status_t iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi, iterFunc callFunc, void* callArg) { ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle); if (zipFile == NULL) { return INSTALL_FAILED_INVALID_APK; } if (initApkScanLib() == LIB_INITED_AND_SUCCESS) { PFilterObject filter = GetFilterObjectFunc(zipFile->getFileDescriptor()); if (filter != NULL) { const ScopedUtfChars cpuAbi(env, javaCpuAbi); if (cpuAbi.c_str() == NULL) { // This would've thrown, so this return code isn't observable by // Java. return INSTALL_FAILED_INVALID_APK; } LibFileDealer param; param.zipFile = zipFile; param.callFunc = callFunc; param.env = env; param.callArg = callArg; param.cpuAbi = &cpuAbi; param.ret = INSTALL_SUCCEEDED; if (0 == FilterLibraryFunc(filter, dealLibFile, ¶m)) { return param.ret; } } } UniquePtr<NativeLibrariesIterator> it(NativeLibrariesIterator::create(zipFile)); if (it.get() == NULL) { return INSTALL_FAILED_INVALID_APK; } const ScopedUtfChars cpuAbi(env, javaCpuAbi); if (cpuAbi.c_str() == NULL) { // This would've thrown, so this return code isn't observable by // Java. return INSTALL_FAILED_INVALID_APK; } ZipEntryRO entry = NULL; while ((entry = it->next()) != NULL) { const char* fileName = it->currentEntry(); const char* lastSlash = it->lastSlash(); // Check to make sure the CPU ABI of this file is one we support. const char* cpuAbiOffset = fileName + APK_LIB_LEN; const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset; if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) { install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1); if (ret != INSTALL_SUCCEEDED) { ALOGV("Failure for entry %s", lastSlash + 1); return ret; } } } return INSTALL_SUCCEEDED; }
解压APK,根据确定的找到的CPUABI,只拷贝对应目录下的so库。
拷贝完so库后,就要设置primaryCpuAbi和secondaryCpuAbi,primaryCpuAbi 的值来决定我们的程序是运行在32位还是64位下的。
primaryCpuAbi和secondaryCpuAbi设置的逻辑在derivePackageAbi()中。
if (isMultiArch(pkg.applicationInfo)) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. if (pkg.cpuAbiOverride != null && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) { Slog.w(TAG, "Ignoring abiOverride for multi arch application."); } int abi32 = PackageManager.NO_NATIVE_LIBRARIES; int abi64 = PackageManager.NO_NATIVE_LIBRARIES; if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { if (extractLibs) { abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS, useIsaSpecificSubdirs); } else { abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS); } } maybeThrowExceptionForMultiArchCopy( "Error unpackaging 32 bit native libs for multiarch app.", abi32); if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { if (extractLibs) { abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS, useIsaSpecificSubdirs); } else { abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS); } } maybeThrowExceptionForMultiArchCopy( "Error unpackaging 64 bit native libs for multiarch app.", abi64); if (abi64 >= 0) { pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64]; } if (abi32 >= 0) { final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32]; if (abi64 >= 0) { if (pkg.use32bitAbi) { pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi; pkg.applicationInfo.primaryCpuAbi = abi; } else { pkg.applicationInfo.secondaryCpuAbi = abi; } } else { pkg.applicationInfo.primaryCpuAbi = abi; } } } else { String[] abiList = (cpuAbiOverride != null) ? new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS; // Enable gross and lame hacks for apps that are built with old // SDK tools. We must scan their APKs for renderscript bitcode and // not launch them if it's present. Don't bother checking on devices // that don't have 64 bit support. boolean needsRenderScriptOverride = false; if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null && NativeLibraryHelper.hasRenderscriptBitcode(handle)) { abiList = Build.SUPPORTED_32_BIT_ABIS; needsRenderScriptOverride = true; } final int copyRet; if (extractLibs) { copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs); } else { copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList); } if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Error unpackaging native libs for app, errorCode=" + copyRet); } if (copyRet >= 0) { pkg.applicationInfo.primaryCpuAbi = abiList[copyRet]; } else if (copyRet == PackageManager.NO_NATIVE_LIBRARIES && cpuAbiOverride != null) { pkg.applicationInfo.primaryCpuAbi = cpuAbiOverride; } else if (needsRenderScriptOverride) { pkg.applicationInfo.primaryCpuAbi = abiList[0]; } }
3.在data/data/apk相关目录 下的lib 创建软链接到真正放lib的地方
调用到了installd,最后调用symlink来创建软链接
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) { final String nativeLibPath = app.nativeLibraryDir; try { mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName, nativeLibPath, userId); } catch (InstallerException e) { Slog.e(TAG, "Failed to link native for " + packageName + ": " + e); } } }
可以查看手机目录
相关文章推荐
- PackageManagerService安装流程
- Android PackageManagerService分析二:安装APK
- PackageManagerService(Android5.1)深入分析(四)安装应用
- APK的安装过程分析(PackageManagerService启动过程)
- Android framework 应用安装流程 分析 PackageManagerService(Android5.1)
- Android应用管理四 -- APK包的安装、卸载和优化(PackageManagerService)
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)(一)
- Android7.0 PackageManagerService (3) APK安装
- Android Fk-PKMS(2) PackageManagerService之应用的安装与卸载
- Android6.0 PackageManagerService 安装lib
- Android L-preview PackageManagerService启动、安装和卸载分析
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)(二)
- Android5.1--APK包的安装、卸载和优化(PackageManagerService)
- Android apk安装管理(PackageManagerService 分析)
- 通过 PackageManagerService 接口queryIntentActivities 获取 全部 安装的apk信息
- PackageManagerService源码分析之安装应用(四)
- PackageManagerService——掌管APP的安装、卸载和查询
- PackageManagerService安装APK流程
- Android6.0 PackageManagerService(PMS)-安装
- PackageManagerService中运用inotify去监控目录中的APK更新、安装和删除