Merge "Use speed-profile with the cloud profile for apks loaded by other apps." into tm-dev
This commit is contained in:
@@ -89,6 +89,14 @@ public class Installer extends SystemService {
|
|||||||
*/
|
*/
|
||||||
public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
|
public static final int PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The results of {@code getOdexVisibility}. See
|
||||||
|
* {@link #getOdexVisibility(String, String, String)} for details.
|
||||||
|
*/
|
||||||
|
public static final int ODEX_NOT_FOUND = 0;
|
||||||
|
public static final int ODEX_IS_PUBLIC = 1;
|
||||||
|
public static final int ODEX_IS_PRIVATE = 2;
|
||||||
|
|
||||||
|
|
||||||
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
|
public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
|
||||||
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
|
public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
|
||||||
@@ -866,6 +874,15 @@ public class Installer extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the app profile for the package at the given path:
|
||||||
|
* <ul>
|
||||||
|
* <li>Creates the current profile for the given user ID, unless the user ID is
|
||||||
|
* {@code UserHandle.USER_NULL}.</li>
|
||||||
|
* <li>Merges the profile from the dex metadata file (if present) into the reference
|
||||||
|
* profile.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
|
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
|
||||||
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
|
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
|
||||||
if (!checkBeforeRemote()) return false;
|
if (!checkBeforeRemote()) return false;
|
||||||
@@ -1016,6 +1033,33 @@ public class Installer extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the visibility of the optimized artifacts.
|
||||||
|
*
|
||||||
|
* @param packageName name of the package.
|
||||||
|
* @param apkPath path to the APK.
|
||||||
|
* @param instructionSet instruction set of the optimized artifacts.
|
||||||
|
* @param outputPath path to the directory that contains the optimized artifacts (i.e., the
|
||||||
|
* directory that {@link #dexopt} outputs to).
|
||||||
|
*
|
||||||
|
* @return {@link #ODEX_NOT_FOUND} if the optimized artifacts are not found, or
|
||||||
|
* {@link #ODEX_IS_PUBLIC} if the optimized artifacts are accessible by all apps, or
|
||||||
|
* {@link #ODEX_IS_PRIVATE} if the optimized artifacts are only accessible by this app.
|
||||||
|
*
|
||||||
|
* @throws InstallerException if failed to get the visibility of the optimized artifacts.
|
||||||
|
*/
|
||||||
|
public int getOdexVisibility(String packageName, String apkPath, String instructionSet,
|
||||||
|
String outputPath) throws InstallerException {
|
||||||
|
if (!checkBeforeRemote()) return -1;
|
||||||
|
BlockGuard.getVmPolicy().onPathAccess(apkPath);
|
||||||
|
BlockGuard.getVmPolicy().onPathAccess(outputPath);
|
||||||
|
try {
|
||||||
|
return mInstalld.getOdexVisibility(packageName, apkPath, instructionSet, outputPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw InstallerException.from(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InstallerException extends Exception {
|
public static class InstallerException extends Exception {
|
||||||
public InstallerException(String detailMessage) {
|
public InstallerException(String detailMessage) {
|
||||||
super(detailMessage);
|
super(detailMessage);
|
||||||
|
|||||||
@@ -319,28 +319,42 @@ public class PackageDexOptimizer {
|
|||||||
|
|
||||||
String profileName = ArtManager.getProfileName(
|
String profileName = ArtManager.getProfileName(
|
||||||
i == 0 ? null : pkg.getSplitNames()[i - 1]);
|
i == 0 ? null : pkg.getSplitNames()[i - 1]);
|
||||||
|
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|
||||||
|
|| packageUseInfo.isUsedByOtherApps(path);
|
||||||
|
String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter());
|
||||||
|
// If the app is used by other apps, we must not use the existing profile because it
|
||||||
|
// may contain user data, unless the profile is newly created on install.
|
||||||
|
final boolean resetProfile = isProfileGuidedCompilerFilter(compilerFilter)
|
||||||
|
&& isUsedByOtherApps
|
||||||
|
&& options.getCompilationReason() != PackageManagerService.REASON_INSTALL;
|
||||||
|
|
||||||
String dexMetadataPath = null;
|
String dexMetadataPath = null;
|
||||||
if (options.isDexoptInstallWithDexMetadata()) {
|
if (options.isDexoptInstallWithDexMetadata() || resetProfile) {
|
||||||
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
|
File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(new File(path));
|
||||||
dexMetadataPath = dexMetadataFile == null
|
dexMetadataPath = dexMetadataFile == null
|
||||||
? null : dexMetadataFile.getAbsolutePath();
|
? null : dexMetadataFile.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|
|
||||||
|| packageUseInfo.isUsedByOtherApps(path);
|
|
||||||
final String compilerFilter = getRealCompilerFilter(pkg,
|
|
||||||
options.getCompilerFilter(), isUsedByOtherApps);
|
|
||||||
// If we don't have to check for profiles updates assume
|
// If we don't have to check for profiles updates assume
|
||||||
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
|
// PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA which will be a no-op with respect to
|
||||||
// profiles.
|
// profiles.
|
||||||
final int profileAnalysisResult = options.isCheckForProfileUpdates()
|
int profileAnalysisResult = PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
|
||||||
? analyseProfiles(pkg, sharedGid, profileName, compilerFilter)
|
if (resetProfile) {
|
||||||
: PROFILE_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
|
if (!resetProfile(pkg, profileName, path, dexMetadataPath)) {
|
||||||
|
// Fall back to use the shared filter.
|
||||||
|
compilerFilter =
|
||||||
|
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
|
||||||
|
PackageManagerService.REASON_SHARED);
|
||||||
|
}
|
||||||
|
} else if (options.isCheckForProfileUpdates()) {
|
||||||
|
profileAnalysisResult =
|
||||||
|
analyseProfiles(pkg, sharedGid, profileName, compilerFilter);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
|
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
|
||||||
// flags.
|
// flags.
|
||||||
final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, options);
|
final int dexoptFlags = getDexFlags(pkg, pkgSetting, compilerFilter, resetProfile,
|
||||||
|
options);
|
||||||
|
|
||||||
for (String dexCodeIsa : dexCodeInstructionSets) {
|
for (String dexCodeIsa : dexCodeInstructionSets) {
|
||||||
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
|
int newResult = dexOptPath(pkg, pkgSetting, path, dexCodeIsa, compilerFilter,
|
||||||
@@ -390,6 +404,30 @@ public class PackageDexOptimizer {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the profiles of the dex file at {@code path} belonging to the package {@code pkg} to
|
||||||
|
* the initial state as if the package is newly installed. Returns true on success, or false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
@GuardedBy("mInstallLock")
|
||||||
|
private boolean resetProfile(AndroidPackage pkg, String profileName, String path,
|
||||||
|
@Nullable String dexMetadataPath) {
|
||||||
|
if (dexMetadataPath != null) {
|
||||||
|
try {
|
||||||
|
mInstaller.clearAppProfiles(pkg.getPackageName(), profileName);
|
||||||
|
final int appId = UserHandle.getAppId(pkg.getUid());
|
||||||
|
mInstaller.prepareAppProfile(pkg.getPackageName(), UserHandle.USER_NULL,
|
||||||
|
appId, profileName, path, dexMetadataPath);
|
||||||
|
return true;
|
||||||
|
} catch (InstallerException e) {
|
||||||
|
Slog.w(TAG, "Failed to reset profile", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs dexopt on the {@code path} belonging to the package {@code pkg}.
|
* Performs dexopt on the {@code path} belonging to the package {@code pkg}.
|
||||||
*
|
*
|
||||||
@@ -405,15 +443,15 @@ public class PackageDexOptimizer {
|
|||||||
String classLoaderContext, int dexoptFlags, int uid,
|
String classLoaderContext, int dexoptFlags, int uid,
|
||||||
CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
|
CompilerStats.PackageStats packageStats, boolean downgrade, String profileName,
|
||||||
String dexMetadataPath, int compilationReason) {
|
String dexMetadataPath, int compilationReason) {
|
||||||
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
|
String oatDir = getPackageOatDirIfSupported(pkg,
|
||||||
profileAnalysisResult, downgrade);
|
pkgSetting.getTransientState().isUpdatedSystemApp());
|
||||||
|
|
||||||
|
int dexoptNeeded = getDexoptNeeded(pkg.getPackageName(), path, isa, compilerFilter,
|
||||||
|
classLoaderContext, profileAnalysisResult, downgrade, dexoptFlags, oatDir);
|
||||||
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
|
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
|
||||||
return DEX_OPT_SKIPPED;
|
return DEX_OPT_SKIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
String oatDir = getPackageOatDirIfSupported(pkg,
|
|
||||||
pkgSetting.getTransientState().isUpdatedSystemApp());
|
|
||||||
|
|
||||||
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
|
Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path
|
||||||
+ " pkg=" + pkg.getPackageName() + " isa=" + isa
|
+ " pkg=" + pkg.getPackageName() + " isa=" + isa
|
||||||
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
|
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
|
||||||
@@ -456,6 +494,7 @@ public class PackageDexOptimizer {
|
|||||||
/**
|
/**
|
||||||
* Perform dexopt (if needed) on a system server code path).
|
* Perform dexopt (if needed) on a system server code path).
|
||||||
*/
|
*/
|
||||||
|
@GuardedBy("mInstallLock")
|
||||||
@DexOptResult
|
@DexOptResult
|
||||||
public int dexoptSystemServerPath(
|
public int dexoptSystemServerPath(
|
||||||
String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
|
String dexPath, PackageDexUsage.DexUseInfo dexUseInfo, DexoptOptions options) {
|
||||||
@@ -466,12 +505,15 @@ public class PackageDexOptimizer {
|
|||||||
int result = DEX_OPT_SKIPPED;
|
int result = DEX_OPT_SKIPPED;
|
||||||
for (String isa : dexUseInfo.getLoaderIsas()) {
|
for (String isa : dexUseInfo.getLoaderIsas()) {
|
||||||
int dexoptNeeded = getDexoptNeeded(
|
int dexoptNeeded = getDexoptNeeded(
|
||||||
|
PackageManagerService.PLATFORM_PACKAGE_NAME,
|
||||||
dexPath,
|
dexPath,
|
||||||
isa,
|
isa,
|
||||||
options.getCompilerFilter(),
|
options.getCompilerFilter(),
|
||||||
dexUseInfo.getClassLoaderContext(),
|
dexUseInfo.getClassLoaderContext(),
|
||||||
PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
|
PROFILE_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES,
|
||||||
/* downgrade= */ false);
|
/* downgrade= */ false,
|
||||||
|
dexoptFlags,
|
||||||
|
/* oatDir= */ null);
|
||||||
|
|
||||||
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
|
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
|
||||||
continue;
|
continue;
|
||||||
@@ -714,7 +756,7 @@ public class PackageDexOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the compiler filter that should be used to optimize the package code.
|
* Returns the compiler filter that should be used to optimize the secondary dex.
|
||||||
* The target filter will be updated if the package code is used by other apps
|
* The target filter will be updated if the package code is used by other apps
|
||||||
* or if it has the safe mode flag set.
|
* or if it has the safe mode flag set.
|
||||||
*/
|
*/
|
||||||
@@ -754,12 +796,12 @@ public class PackageDexOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the compiler filter that should be used to optimize the package code.
|
* Returns the compiler filter that should be used to optimize the primary dex.
|
||||||
* The target filter will be updated if the package code is used by other apps
|
* The target filter will be updated if the package has the safe mode flag set. Note that this
|
||||||
* or if it has the safe mode flag set.
|
* method does NOT take other app use into account. The caller should be responsible for
|
||||||
|
* handling the case where the package code is used by other apps.
|
||||||
*/
|
*/
|
||||||
private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter,
|
private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
|
||||||
boolean isUsedByOtherApps) {
|
|
||||||
// When an app or priv app is configured to run out of box, only verify it.
|
// When an app or priv app is configured to run out of box, only verify it.
|
||||||
if (pkg.isUseEmbeddedDex()
|
if (pkg.isUseEmbeddedDex()
|
||||||
|| (pkg.isPrivileged()
|
|| (pkg.isPrivileged()
|
||||||
@@ -783,12 +825,6 @@ public class PackageDexOptimizer {
|
|||||||
return getSafeModeCompilerFilter(targetCompilerFilter);
|
return getSafeModeCompilerFilter(targetCompilerFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
|
|
||||||
// If the dex files is used by other apps, apply the shared filter.
|
|
||||||
return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
|
|
||||||
PackageManagerService.REASON_SHARED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetCompilerFilter;
|
return targetCompilerFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,14 +835,16 @@ public class PackageDexOptimizer {
|
|||||||
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
|
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
|
||||||
return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
|
return getDexFlags((info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0,
|
||||||
info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
|
info.getHiddenApiEnforcementPolicy(), info.splitDependencies,
|
||||||
info.requestsIsolatedSplitLoading(), compilerFilter, options);
|
info.requestsIsolatedSplitLoading(), compilerFilter, false /* resetProfile */,
|
||||||
|
options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
|
private int getDexFlags(AndroidPackage pkg, @NonNull PackageStateInternal pkgSetting,
|
||||||
String compilerFilter, DexoptOptions options) {
|
String compilerFilter, boolean resetProfile, DexoptOptions options) {
|
||||||
return getDexFlags(pkg.isDebuggable(),
|
return getDexFlags(pkg.isDebuggable(),
|
||||||
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
|
AndroidPackageUtils.getHiddenApiEnforcementPolicy(pkg, pkgSetting),
|
||||||
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
|
pkg.getSplitDependencies(), pkg.isIsolatedSplitLoading(), compilerFilter,
|
||||||
options);
|
resetProfile, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -815,13 +853,15 @@ public class PackageDexOptimizer {
|
|||||||
*/
|
*/
|
||||||
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
|
private int getDexFlags(boolean debuggable, int hiddenApiEnforcementPolicy,
|
||||||
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
|
SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading,
|
||||||
String compilerFilter, DexoptOptions options) {
|
String compilerFilter, boolean resetProfile, DexoptOptions options) {
|
||||||
// Profile guide compiled oat files should not be public unles they are based
|
// Profile guide compiled oat files should not be public unles they are based
|
||||||
// on profiles from dex metadata archives.
|
// on profiles from dex metadata archives.
|
||||||
// The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
|
// The flag isDexoptInstallWithDexMetadata applies only on installs when we know that
|
||||||
// the user does not have an existing profile.
|
// the user does not have an existing profile.
|
||||||
|
// The flag resetProfile applies only when the existing profile is already reset.
|
||||||
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
|
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
|
||||||
boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata();
|
boolean isPublic = !isProfileGuidedFilter || options.isDexoptInstallWithDexMetadata()
|
||||||
|
|| resetProfile;
|
||||||
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
|
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
|
||||||
// Some apps are executed with restrictions on hidden API usage. If this app is one
|
// Some apps are executed with restrictions on hidden API usage. If this app is one
|
||||||
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
|
// of them, pass a flag to dexopt to enable the same restrictions during compilation.
|
||||||
@@ -866,8 +906,19 @@ public class PackageDexOptimizer {
|
|||||||
* Assesses if there's a need to perform dexopt on {@code path} for the given
|
* Assesses if there's a need to perform dexopt on {@code path} for the given
|
||||||
* configuration (isa, compiler filter, profile).
|
* configuration (isa, compiler filter, profile).
|
||||||
*/
|
*/
|
||||||
private int getDexoptNeeded(String path, String isa, String compilerFilter,
|
@GuardedBy("mInstallLock")
|
||||||
String classLoaderContext, int profileAnalysisResult, boolean downgrade) {
|
private int getDexoptNeeded(String packageName, String path, String isa, String compilerFilter,
|
||||||
|
String classLoaderContext, int profileAnalysisResult, boolean downgrade,
|
||||||
|
int dexoptFlags, String oatDir) {
|
||||||
|
final boolean shouldBePublic = (dexoptFlags & DEXOPT_PUBLIC) != 0;
|
||||||
|
// If the artifacts should be public while the current artifacts are not, we should
|
||||||
|
// re-compile anyway.
|
||||||
|
if (shouldBePublic && isOdexPrivate(packageName, path, isa, oatDir)) {
|
||||||
|
// Ensure compilation by pretending a compiler filter change on the apk/odex location
|
||||||
|
// (the reason for the '-'. A positive value means the 'oat' location).
|
||||||
|
return adjustDexoptNeeded(-DexFile.DEX2OAT_FOR_FILTER);
|
||||||
|
}
|
||||||
|
|
||||||
int dexoptNeeded;
|
int dexoptNeeded;
|
||||||
try {
|
try {
|
||||||
// A profile guided optimizations with an empty profile is essentially 'verify' and
|
// A profile guided optimizations with an empty profile is essentially 'verify' and
|
||||||
@@ -901,6 +952,18 @@ public class PackageDexOptimizer {
|
|||||||
return compilerFilter.endsWith("-profile");
|
return compilerFilter.endsWith("-profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns true if the current artifacts of the app are private to the app itself. */
|
||||||
|
@GuardedBy("mInstallLock")
|
||||||
|
private boolean isOdexPrivate(String packageName, String path, String isa, String oatDir) {
|
||||||
|
try {
|
||||||
|
return mInstaller.getOdexVisibility(packageName, path, isa, oatDir)
|
||||||
|
== Installer.ODEX_IS_PRIVATE;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.w(TAG, "Failed to get odex visibility for " + path, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if there is an update on the profile information of the {@code pkg}.
|
* Checks if there is an update on the profile information of the {@code pkg}.
|
||||||
* If the compiler filter is not profile guided the method returns a safe default:
|
* If the compiler filter is not profile guided the method returns a safe default:
|
||||||
|
|||||||
Reference in New Issue
Block a user