am b9048634: Scan package to derive ABIs before optimizing.
* commit 'b904863476991d8540d37d542c0a49b78deab680': Scan package to derive ABIs before optimizing.
This commit is contained in:
@@ -6301,7 +6301,6 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
|
||||
final String path = scanFile.getPath();
|
||||
final String codePath = pkg.applicationInfo.getCodePath();
|
||||
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
|
||||
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
|
||||
setBundledAppAbisAndRoots(pkg, pkgSetting);
|
||||
@@ -6327,127 +6326,27 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
setNativeLibraryPaths(pkg);
|
||||
} else {
|
||||
// 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.
|
||||
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
|
||||
deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
|
||||
} else {
|
||||
// Verify the ABIs haven't changed since we last deduced them.
|
||||
String oldPrimaryCpuAbi = pkg.applicationInfo.primaryCpuAbi;
|
||||
String oldSecondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi;
|
||||
|
||||
// Give ourselves some initial paths; we'll come back for another
|
||||
// pass once we've determined ABI below.
|
||||
setNativeLibraryPaths(pkg);
|
||||
|
||||
final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
|
||||
final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
|
||||
final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
|
||||
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(scanFile);
|
||||
// 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 (isAsec) {
|
||||
abi32 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
|
||||
} else {
|
||||
abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
|
||||
useIsaSpecificSubdirs);
|
||||
}
|
||||
}
|
||||
|
||||
maybeThrowExceptionForMultiArchCopy(
|
||||
"Error unpackaging 32 bit native libs for multiarch app.", abi32);
|
||||
|
||||
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
|
||||
if (isAsec) {
|
||||
abi64 = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
|
||||
} else {
|
||||
abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
|
||||
useIsaSpecificSubdirs);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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 (isAsec) {
|
||||
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
|
||||
} else {
|
||||
copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
|
||||
nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
// TODO: The only purpose of this code is to update the native library paths
|
||||
// based on the final install location. We can simplify this and avoid having
|
||||
// to scan the package again.
|
||||
deriveNonSystemPackageAbi(pkg, scanFile, cpuAbiOverride, false /* extract libs */);
|
||||
if (!TextUtils.equals(oldPrimaryCpuAbi, pkg.applicationInfo.primaryCpuAbi)) {
|
||||
throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
|
||||
+ oldPrimaryCpuAbi + "-> " + pkg.applicationInfo.primaryCpuAbi);
|
||||
}
|
||||
} 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);
|
||||
if (!TextUtils.equals(oldSecondaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi)) {
|
||||
throw new IllegalStateException("unexpected abi change for " + pkg.packageName + " ("
|
||||
+ oldSecondaryCpuAbi + "-> " + pkg.applicationInfo.secondaryCpuAbi);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path);
|
||||
final int[] userIds = sUserManager.getUserIds();
|
||||
@@ -6478,9 +6377,21 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
|
||||
}
|
||||
|
||||
// If there's a mismatch between the abi-override in the package setting
|
||||
// and the abiOverride specified for the install. Warn about this because we
|
||||
// would've already compiled the app without taking the package setting into
|
||||
// account.
|
||||
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
|
||||
if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
|
||||
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
|
||||
" for package: " + pkg.packageName);
|
||||
}
|
||||
}
|
||||
|
||||
pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
|
||||
pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
|
||||
pkgSetting.cpuAbiOverrideString = cpuAbiOverride;
|
||||
|
||||
// Copy the derived override back to the parsed package, so that we can
|
||||
// update the package settings accordingly.
|
||||
pkg.cpuAbiOverride = cpuAbiOverride;
|
||||
@@ -6973,6 +6884,144 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
return pkg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the ABI of a non-system package located at {@code scanFile}. This information
|
||||
* is derived purely on the basis of the contents of {@code scanFile} and
|
||||
* {@code cpuAbiOverride}.
|
||||
*
|
||||
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
|
||||
*/
|
||||
public void deriveNonSystemPackageAbi(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.
|
||||
if (pkg.isForwardLocked() || isExternal(pkg)) {
|
||||
extractLibs = false;
|
||||
}
|
||||
|
||||
final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
|
||||
final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
|
||||
|
||||
NativeLibraryHelper.Handle handle = null;
|
||||
try {
|
||||
handle = NativeLibraryHelper.Handle.create(scanFile);
|
||||
// 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
|
||||
* i.e, so that all packages can be run inside a single process if required.
|
||||
@@ -11566,6 +11615,16 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
|
||||
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
|
||||
scanFlags |= SCAN_NO_DEX;
|
||||
|
||||
try {
|
||||
deriveNonSystemPackageAbi(pkg, new File(pkg.codePath), args.abiOverride,
|
||||
true /* extract libs */);
|
||||
} catch (PackageManagerException pme) {
|
||||
Slog.e(TAG, "Error deriving application ABI", pme);
|
||||
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error ");
|
||||
return;
|
||||
}
|
||||
|
||||
// Run dexopt before old package gets removed, to minimize time when app is unavailable
|
||||
int result = mPackageDexOptimizer
|
||||
.performDexOpt(pkg, null /* instruction sets */, true /* forceDex */,
|
||||
|
||||
Reference in New Issue
Block a user