packages.xml

一个 apk 安装后,会在 /data/system/packages.xml 中添加纪录,例如:

其中的 primaryCpuAbi 决定了该应用是 32 位的还是 64 位的。

这个值由 PackageManagerService 在做 scanPackageLI 的时候决定,具体这个值的得出有一个公式化的过程,主要就是判断这个 apk 有没有使用 native 的库,如果使用了,那就看使用了的是 32 位的还是 64 位的,另外还要看系统支持的是 32 位还是 64 位的。

确定的时机

安装一个 apk 时

会调用:private void installPackageLI(InstallArgs args, PackageInstalledInfo res), 在这个函数中会调用:

private static void derivePackageAbi(PackageParser.Package pkg, File scanFile, String cpuAbiOverride, boolean extractLibs, File appLib32InstallDir)

系统启动时

在 PKMS 的构造函数中,会调用 scanDirLI() 逐个解析系统里的所有 apk 文件,这个函数会调用: scanPackageLI,

而 scanPackageLI 会调用: scanPackageDirtyLI, 在 scanPackageDirtyLI 函数中会调用: derivePackageAbi 等函数来确定 ABI

public PackageManagerService(Context context, Installer installer,

boolean factoryTest, boolean onlyCore) {

... ...

scanDirLI();

... ...

// 当所有的 apk 文件解析完之后,对使用了相同 UID 的 apk, 调用 adjustCpuAbisForSharedUserLPw

for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {

// setting.packages 是所有使用相同 UID 的 apk 的集合

adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,

false /* force dexopt */, false /* defer dexopt */);

}

... ...

}

ActivityManagerService 启动一个应用时

启动时,如果没能找到有确认的 primaryCpuAbi,就使用 ro.product.cpu.abilist 这个 property 的值的第一项作为它关联的 ABI

ABI 确定过程

scanPackageDirtyLI

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,

final int policyFlags, final int scanFlags, long currentTime, @Nullable UserHandle user),在这个函数中会调用:

......

// 如果不是第一次开机或者升级,就从 mSettings 中读取 PackageSetting 类型的值,再将其中存储的关于 ABI 的值保存到临时变量中

if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {

PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);

if (foundPs != null) {

primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;

secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;

}

}

......

if ((scanFlags & SCAN_NEW_INSTALL) == 0) {

if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {

// 是第一次开机或者升级,调用 derivePackageAbi 方法解析abi路径等相关信息存到 pkg 中

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");

final boolean extractNativeLibs = !pkg.isLibrary();

derivePackageAbi(pkg, scanFile, cpuAbiOverride, extractNativeLibs, mAppLib32InstallDir);

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

// 如果是 system app, 并且通过 derivePackageAbi() 方法没有确定 primaryCpuAbi 的值,那么尝试用下面的方法来确定

// 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 == null) {

// 如果是 system app,并且这个 app 没有通过上面的函数找到 primaryCpuAbi 的值

setBundledAppAbisAndRoots(pkg, pkgSetting);

// setNativeLibraryPaths 方法会根据 CpuAbi 的值确定 apk 使用的 so 库的安装路径

setNativeLibraryPaths(pkg, mAppLib32InstallDir);

}

} else {

// 如果不是第一次开机或者升级,将上面第一次判断得到的临时变量的值复制到 pkg 中

// This is not a first boot or an upgrade, don't bother deriving the

// ABI during the scan. Instead, trust the value that was stored in the

// package setting.

pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;

pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;

setNativeLibraryPaths(pkg, mAppLib32InstallDir);

if (DEBUG_ABI_SELECTION) {

Slog.i(TAG, "Using ABIS and native lib paths from settings : " +

pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +

pkg.applicationInfo.secondaryCpuAbi);

}

}

} else {

......

}

// 当前解析的 apk 是 framework-res.apk, 对这个特殊的apk, 让它的 ABI 的值与系统相同。在我这里,它就是 arm64-v8a

// This is a special case for the "system" package, where the ABI is

// dictated by the zygote configuration (and init.rc). We should keep track

// of this ABI so that we can deal with "normal" applications that run under

// the same UID correctly.

if (mPlatformPackage == pkg) {

pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ?

Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];

}

derivePackageAbi

private static void derivePackageAbi(PackageParser.Package pkg, File scanFile, String cpuAbiOverride, boolean extractLibs, File appLib32InstallDir)

throws PackageManagerException {

// 这里会先设置一个默认的 so 库安装路径

// Give ourselves some initial paths; we'll come back for another

// pass once we've determined ABI below.

setNativeLibraryPaths(pkg, appLib32InstallDir);

// 如果是系统级别的 APP 则不用每次都提取

// 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;

// 是否有设置过 nativeLibraryRootRequiresIsa

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.

// 获取本地库的 File

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)) {

// 这里处理的是支持两种 abi 的 apk, 这种 apk 的 AndroidManifest.xml 里会设置 android:multiarch 为 true

// 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;

// 如果有 设备支持的 32 位 abi

if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {

if (extractLibs) {

// 如果需要导出

// 调用 NativeLibraryHelper 的 copyNativeBinariesForSupportedAbi 方法进行 so 库拷贝

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");

abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,

nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,

useIsaSpecificSubdirs);

} else {

// 调用 NativeLibraryHelper 的 findSupportedAbi 获取该应用的 so 库,在当前系统所能支持的最小 ABI 索引值

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");

abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);

}

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

}

// Shared library native code should be in the APK zip aligned

if (abi32 >= 0 && pkg.isLibrary() && extractLibs) {

throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,

"Shared library native lib extraction not supported");

}

// 检查是否有异常

maybeThrowExceptionForMultiArchCopy(

"Error unpackaging 32 bit native libs for multiarch app.", abi32);

if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {

if (extractLibs) {

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");

abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,

nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,

useIsaSpecificSubdirs);

} else {

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");

abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);

}

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

}

maybeThrowExceptionForMultiArchCopy(

"Error unpackaging 64 bit native libs for multiarch app.", abi64);

if (abi64 >= 0) {

// 如果 abi64 有值,则说明有支持的 64 位库

// Shared library native libs should be in the APK zip aligned

if (extractLibs && pkg.isLibrary()) {

throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,

"Shared library native lib extraction not supported");

}

// 设置第一顺位的 abi 即 primaryCpuAbi 为支持的 64 位 ABI

pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[abi64];

}

if (abi32 >= 0) {

final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32];

if (abi64 >= 0) {

// 如果同时还支持 64 位

if (pkg.use32bitAbi) {

pkg.applicationInfo.secondaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;

pkg.applicationInfo.primaryCpuAbi = abi;

} else {

pkg.applicationInfo.secondaryCpuAbi = abi;

}

} else {

pkg.applicationInfo.primaryCpuAbi = abi;

}

}

} else {

// 不支持多平台

// 获取设备中支持的 CPU 架构

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.

// 是否需要 RenderScript 重写,RenderScript 是 Android 平台的一种类 C 脚本语言

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) {

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");

// 这是一个 JNI 函数,作用就是根据 apk 包里的 lib/ 目录下的 .so 的 ABI 确定返回值,并且把 apk 的 lib 库文件 copy 到创建的 lib 目录

copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,

nativeLibraryRoot, abiList, useIsaSpecificSubdirs);

} else {

Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");

// 这是一个 JNI 函数,作用就是根据 apk 包里的 lib/ 目录下的 .so 的 ABI 确定返回值

copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);

}

Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);

// 判断是否出现异常

if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {

throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,

"Error unpackaging native libs for app, errorCode=" + copyRet);

}

// 根据 copyRet 的值,确定当前 app 的 primaryCpuAbi 值

if (copyRet >= 0) {

// Shared libraries that have native libs must be multi-architecture

if (pkg.isLibrary()) {

throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,

"Shared library with native libs must be multiarch");

}

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];

}

// 到此处,如果是 arm64-v8a, 并且 copyRet == 1,那么 pkg.applicationInfo.primaryCpuAbi 为 “armeabi-v7a”

}

} catch (IOException ioe) {

Slog.e(TAG, "Unable to get canonical file " + ioe.toString());

} finally {

IoUtils.closeQuietly(handle);

}

// 到这里有一些 app 已经确定了 primaryCpuAbi 的值,所以再调一次这个函数,更新它使用的 .so 库的安装位置

// 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, appLib32InstallDir);

}

其中 NativeLibraryHelper.findSupportedAbi 实现在:frameworks/base/core/java/com/android/internal/content/NativeLibraryHelper.java,

这个函数会调用: nativeFindSupportedAbi, 该函数实现在:frameworks/base/core/jni/com_android_internal_content_NativeLibraryHelper.cpp 中,被高通修改过,最终实现函数为:

static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray, jboolean debuggable)

这个的作用是如果 apk 的文件夹下有 so 库,系统会根据 so 库的 ABI 去决定 app 的 ABI

通过这段代码会可以看出:一些 apk 包里 lib 目录下有 .so 文件的,可以通过 .so 文件的 ABI 来确定 app 的 primaryCpuAbi 的值。

对于那些 lib 下没有 .so 文件的 apk, 比如不使用 so 库的或者是系统 app,运行完这个方法之后,primaryCpuAbi 的值仍然是空。

接下来看下 系统app 是如何通过 setBundledAppAbisAndRoots() 方法来确定 primaryCpuAbi 的值的

setBundledAppAbisAndRoots

private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,

PackageSetting pkgSetting) {

final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());

// 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(pkg.applicationInfo.sourceDir);

// 使用 setBundledAppAbi() 方法确定 primaryCpuAbi 值

setBundledAppAbi(pkg, apkRoot, apkName);

// pkgSetting might be null during rescan following uninstall of updates

// to a bundled app, so accommodate that possibility. The settings in

// that case will be established later from the parsed package.

//

// If the settings aren't null, sync them up with what we've just derived.

// note that apkRoot isn't stored in the package settings.

if (pkgSetting != null) {

pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;

pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;

}

}

/**

* Deduces the ABI of a bundled app and sets the relevant fields on the

* parsed pkg object.

*

* @param apkRoot the root of the installed apk, something like {@code /system} or {@code /oem}

* under which system libraries are installed.

* @param apkName the name of the installed package.

*/

private static void setBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) {

final File codeFile = new File(pkg.codePath);

final boolean has64BitLibs;

final boolean has32BitLibs;

if (isApkFile(codeFile)) {

// 只有 framework-res.apk 这个包会进这个 if 分支,has64BitLibs 和 has32BitLibs 的值都是 false

// 在前面 scanPackageDirtyLI 里有说过,这个 app 的 primaryCpuAbi 的值是 arm64-v8a

// Monolithic install

has64BitLibs = (new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath())).exists();

has32BitLibs = (new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath())).exists();

} else {

// 对于其它的 app, codeFile 是 apk 所在的路径

// Cluster install

final File rootDir = new File(codeFile, LIB_DIR_NAME);

if (!ArrayUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS)

&& !TextUtils.isEmpty(Build.SUPPORTED_64_BIT_ABIS[0])) {

// 通过判断 /system/app/${APP_NAME}/lib64 这个文件夹是否存在决定 has64BitLibs 的值

final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_64_BIT_ABIS[0]);

has64BitLibs = (new File(rootDir, isa)).exists();

} else {

has64BitLibs = false;

}

if (!ArrayUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS)

&& !TextUtils.isEmpty(Build.SUPPORTED_32_BIT_ABIS[0])) {

// 通过判断 /system/app/${APP_NAME}/lib 这个文件夹是否存在决定 has32BitLibs 的值

final String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_32_BIT_ABIS[0]);

has32BitLibs = (new File(rootDir, isa)).exists();

} else {

has32BitLibs = false;

}

}

// 下面这一段会根据 has64BitLibs 和 has32BitLibs 的值来确定 app 的 primaryCpuAbi 的值

if (has64BitLibs && !has32BitLibs) {

// The package has 64 bit libs, but not 32 bit libs. Its primary

// ABI should be 64 bit. We can safely assume here that the bundled

// native libraries correspond to the most preferred ABI in the list.

pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];

pkg.applicationInfo.secondaryCpuAbi = null;

} else if (has32BitLibs && !has64BitLibs) {

// The package has 32 bit libs but not 64 bit libs. Its primary

// ABI should be 32 bit.

pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];

pkg.applicationInfo.secondaryCpuAbi = null;

} else if (has32BitLibs && has64BitLibs) {

// The application has both 64 and 32 bit bundled libraries. We check

// here that the app declares multiArch support, and warn if it doesn't.

//

// We will be lenient here and record both ABIs. The primary will be the

// ABI that's higher on the list, i.e, a device that's configured to prefer

// 64 bit apps will see a 64 bit primary ABI,

if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {

Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");

}

if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {

pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];

pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];

} else {

pkg.applicationInfo.primaryCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0];

pkg.applicationInfo.secondaryCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0];

}

} else {

pkg.applicationInfo.primaryCpuAbi = null;

pkg.applicationInfo.secondaryCpuAbi = null;

}

}

......

public static String getPreferredInstructionSet() {

return PREFERRED_INSTRUCTION_SET;

}

private static final String PREFERRED_INSTRUCTION_SET =

VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);;

dalvik.system.VMRuntime 实现在:libcore/libart/src/main/java/dalvik/system/VMRuntime.java

public final class VMRuntime {

private static final Map ABI_TO_INSTRUCTION_SET_MAP = new HashMap(16);

static {

ABI_TO_INSTRUCTION_SET_MAP.put("armeabi", "arm");

ABI_TO_INSTRUCTION_SET_MAP.put("armeabi-v7a", "arm");

ABI_TO_INSTRUCTION_SET_MAP.put("mips", "mips");

ABI_TO_INSTRUCTION_SET_MAP.put("mips64", "mips64");

ABI_TO_INSTRUCTION_SET_MAP.put("x86", "x86");

ABI_TO_INSTRUCTION_SET_MAP.put("x86_64", "x86_64");

ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a", "arm64");

}

public static String getInstructionSet(String abi) {

final String instructionSet = ABI_TO_INSTRUCTION_SET_MAP.get(abi);

if (instructionSet == null) {

throw new IllegalArgumentException("Unsupported ABI: " + abi);

}

return instructionSet;

}

public static boolean is64BitInstructionSet(String instructionSet) {

return "arm64".equals(instructionSet) ||

"x86_64".equals(instructionSet) ||

"mips64".equals(instructionSet);

}

public static boolean is64BitAbi(String abi) {

return is64BitInstructionSet(getInstructionSet(abi));

}

根据上面的代码,可以知道:

对 系统app 而言,根据 /system/app/${APP_NAME}/lib 和 /system/app/${APP_NAME}/lib64 这两个文件夹是否存在,来确定它的 primaryCpuAbi 的值。

当然,如果 系统app 不存在上述两个文件夹,那它的 primaryCpuAbi 的值仍然为空,所以在经过 scanPackageDirtyLI() 方法之后,会存在以下四种情况:

无论是 系统app 还是 第三方app, 如果 apk 包里 lib 目录存在 .so 文件,会根据 .so 文件来确定 primaryCpuAbi 的值

如果是 系统app, apk 包里又不存在 .so 文件,就会进一步根据 /system/app/${APP_NAME}/lib 和 /system/app/${APP_NAME}/lib64 这两个文件夹是否存在,来确定它的 primaryCpuAbi 的值

对于 framework-res.apk 为个特殊的apk文件,它的 primaryCpuAbi 的值由虚拟机是什么架构来决定,在我这里,它是 arm64-v8a

对于其余的 apk, 它们的 primaryCpuAbi 的值仍然为空

adjustCpuAbisForSharedUserLPw

先来看下 adjustCpuAbisForSharedUserLPw 的调用位置,在 PKMS 的构造函数里:

public PackageManagerService(Context context, Installer installer,

boolean factoryTest, boolean onlyCore) {

... ...

scanDirLI();

... ...

// 当所有的 apk 文件解析完之后,对使用了相同 UID 的 apk, 调用 adjustCpuAbisForSharedUserLPw

for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {

// setting.packages 是所有使用相同 UID 的 apk 的集合

adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,

false /* force dexopt */, false /* defer dexopt */);

}

... ...

}

adjustCpuAbisForSharedUserLPw 的作用就是调整使用相同 UID 的package 的 primaryCpuAbi 的值,将那些还没有确定 primaryCpuAbi 的 package 用已经确定了的 Abi 的值代替。

这里将是那些没有确定 primaryCpuAbi 的 apk 再次确定 abi 值的最后一次机会,如果在这里还无法确定,那就在启动进程时,使用系统默认值。

private void adjustCpuAbisForSharedUserLPw(Set packagesForUser,

PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) {

String requiredInstructionSet = null;

... ...

PackageSetting requirer = null;

for (PackageSetting ps : packagesForUser) {

if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {

if (ps.primaryCpuAbiString == null) {

continue;

}

// 这个 for 循环的作用就是遍历所有使用相同 UID 的 package,把遍历过程中遇到的第一个确定 primaryCpuAbi

// 的那个 package 取出来,保存到 requirer 中

final String instructionSet = VMRuntime.getInstructionSet(ps.primaryCpuAbiString);

if (requiredInstructionSet == null) {

// 只取第一个被遍历到的

requiredInstructionSet = instructionSet;

requirer = ps;

}

}

}

if (requiredInstructionSet != null) {

String adjustedAbi;

if (requirer != null) {

// 证明在这个集合中找到了已经确定 primaryCpuAbi 的那个 package

adjustedAbi = requirer.primaryCpuAbiString;

} else {

// scannedPackage == null 时,这种情况不存在,所以不考虑这里

}

for (PackageSetting ps : packagesForUser) {

if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {

if (ps.primaryCpuAbiString != null) {

continue;

}

// 将 adjustedAbi 的值给那些使用同一个 UID 并且 primaryCpuAbi 是空的 package

ps.primaryCpuAbiString = adjustedAbi;

if (ps.pkg != null && ps.pkg.applicationInfo != null) {

ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;

... ...

}

}

}

}

}

总结

最后来总结一下 Android 系统确定 app 进程关联哪种 ABI 的流程:

如果 apk 包中 lib 文件夹下有 .so 库,就根据这个 .so 库的架构模式,确定 app 的 primaryCpuAbi 的值

对于 system app, 如果没法通过第一步确定 primaryCpuAbi 的值,PKMS 会根据 /system/app/${APP_NAME}/lib 和 /system/app/${APP_NAME}/lib64 这两个文件夹是否存在,来确定它的 primaryCpuAbi 的值

对于还没有确定的 app, 在最后还会将自己的 primaryCpuAbi 值与和他使用相同 UID 的 package 的值设成一样

对于到这里还没有确认 primaryCpuAbi 的 app,就会在启动进程时使用 ro.product.cpu.abilist 这个 property 的值的第一项作为它关联的 ABI

保存到 package.xml

在 scanPackageDirtyLI 函数的最后部分,会调用 commitPackageSettings 保存获取到的 pkginfo,在 commitPackageSettings 方法中会调用:mSettings.insertPackageSettingLPw(pkgSetting, pkg)

[Settings.java]

void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {

addPackageSettingLPw(p, p.sharedUser);

}

private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {

//这里会加入到mPackages中

mPackages.put(p.name, p);

}

PKMS 的构造函数最后会执行 mSettings.writeLPr() ,writeLPr 函数会把 mPackages 相关信息写入到 package.xml 等文件中。

matlab dpabi安装,Android 8 应用安装时 ABI 确认过程相关推荐

  1. android app安装,Android App更新安装APK

    原标题:Android App更新安装APK 概要 一般地, Android App 都会被要求在App内进行软件更新提示, 让用户下载apk文件, 然后更新安装新版本, 一般过程如下: 检测是否有新 ...

  2. android sdk库 离线安装,android sdk 离线安装

    android的普通安装方法很简单,不必多说. 由于普通安装方法速度很慢,对一般的用户要数小时的时间等待. 为更快速安装,可以采取离线安装方法.即,先分别下载所需包,再安装. 一,首先下载SDK的安装 ...

  3. android go怎么安装,Android studio3.0安装教程-Go语言中文社区

    Android studio是目前开发Android主流的软件 但是因为被墙缘故 ,导致很多人一直refreshiing gradle project 或者其他安装问题 网上虽然有很多解决方法,但是大 ...

  4. 【尝鲜】windows11免虚拟机直接安装Android安卓应用 - 安装Windows Subsystem for Android with Amazon Appstore的方法

    效果图 步骤 主要步骤 win11电脑开启虚拟机支持组件 安装官方的"Windows Subsystem for Android" 安卓子系统 开启安卓子系统,安装apk安卓应用程 ...

  5. android sdk manager安装,Android SDK Manager安装过程

    1.首先要下载安装Java JDK,下载地址:http://pan.baidu.com/share/link?shareid=7368&uk=2148507123 然后在下载最新的Androi ...

  6. Android 无法监听安装,Android关于apk安装成功广播监听

    有这样的应用场景,apk安装成功后需要重启APP,就需要监听完成安装的回调或者广播 public class UpdateReceiver extends BroadcastReceiver { pr ...

  7. android新版本怎么下载安装,android 新版本下载 安装

    1 首先在程序启动的时候 向服务器发送请求 服务器会返回    String  newVerString="2|app.quannaojiaoyu.com......" 2 然后根 ...

  8. windows7怎么安装android,安卓手机安装运行Win7系统教程(图文)

    有些安卓手机用户想在让自己手机中运行Win7系统,这样可以吗?又该怎么来操作呢?在安卓手机中是可以运行Windows系统,不过没有多大的意义,仅仅只是体验,并不能真正想电脑一样操作Win7系统.现在, ...

  9. 三星s5 安装android,三星手机怎么安装软件?三星手机安装被阻止情况的解决办法介绍...

    三星手机安装被阻止怎么回事?智能手机最大的亮点在于可以和电脑一样,自由的安装各种软件,不过某些品牌手机为了保障系统安全,在安装部分软件时会阻止,而导致安装失败.下面小编为大家详细介绍下三星手机安装被阻 ...

  10. 安卓开发日记(1) - 安装 Android 开发环境和 first app

    安装 Android 开发环境 安装 Android Studio 并升级到最新版本(本文使用 1.0.2 版本) 如果没有安装JDK, 安装 64-bit JDK MAC 下需要手动装一下HAXAM ...

最新文章

  1. MySQL基础篇:用户和权限管理
  2. 团队-象棋游戏-开发文档
  3. java comparable接口_Java面试题之Java集合篇三
  4. Ubuntu 14 配置Android Studio的快捷启动方式
  5. 【Tools】Visual Studio 2019专业版下载和安装
  6. C、C++和MFC中文件的操作
  7. 信息学奥赛一本通(1062:最高的分数)
  8. 对《RHCSA/RHCE Red Hat Linux认证学习指南(第6版):EX200 EX300》的评价
  9. 大学c语言电脑考试判卷,全国计算机等级考试判卷的玄机
  10. Python 的多文件和注释
  11. java表头表体动态返回_JAVA LIST 简单分页 集成EXT4 grid表头动态返回
  12. 自动驾驶 7-1 Carla 概述 - 自动驾驶汽车模拟Carla Overview - Self-Driving Car Simulation
  13. [RK3288][Android7.1][Camera] IMX307 mclk 37.125M补丁
  14. Markdown如何修改上传图片的大小
  15. Falsy Bouncer 过滤数组假值
  16. 谷歌电子邮件服务器,谷歌Gmail为什么会能一统美国电邮服务
  17. 规则引擎--Drools之规则文件
  18. 福州农信计算机类待遇怎么样,福建农村信用社联合社待遇怎么样?农信社工资如何...
  19. python爬虫技术可以干什么-利用爬虫技术能做到哪些很酷很有趣很有用的事情?...
  20. python 打包exe_python pyinstaller打包exe报错的解决方法

热门文章

  1. 【Java多线程】写入同一文件,自定义线程池与线程回收利用2
  2. 自娱自乐的小题目(6)
  3. SpringBoot入门篇-HelloWorld案例
  4. linker command failed with exit code 1 (错误总结)
  5. .net core webapi 导出excel(两种方式EPPLUS、NPOI),返回下载地址或文件流
  6. golang 猜数字小游戏
  7. PHP中的数组(排序)
  8. JDK的代码:抱怨FreeType的斜体不好用,自行处理
  9. build.xml:391: javac doesn‘t support the “nativeheaderdir“ attribute
  10. 源码文件编码问题,导致编译的程序运行错误