[framework] Prepare profile for app code paths
This CL is an intermediate step to enable the use of profiles shipped in the dex metadata files. The preparation consist of: - creating the current profile - merging the profile from the dex metadata file (if present) into the reference profile and happens: - after the application data directory is created, to capture system apps. - post-install (right before we dexopt), to capture any new code paths Test: manual (install apps and splits, take OTA) Bug: 30934496 Change-Id: Id36474ab629ad3ffafd24381d30e3d88ac02d576
This commit is contained in:
@@ -153,4 +153,14 @@ public class ArtManager {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the profile name for the given split. If {@code splitName} is null the
|
||||
* method returns the profile name for the base apk.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static String getProfileName(String splitName) {
|
||||
return splitName == null ? "primary.prof" : splitName + ".split.prof";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import android.annotation.AppIdInt;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageStats;
|
||||
import android.os.Build;
|
||||
@@ -535,6 +537,17 @@ public class Installer extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean prepareAppProfile(String pkg, @UserIdInt int userId, @AppIdInt int appId,
|
||||
String profileName, String codePath, String dexMetadataPath) throws InstallerException {
|
||||
if (!checkBeforeRemote()) return false;
|
||||
try {
|
||||
return mInstalld.prepareAppProfile(pkg, userId, appId, profileName, codePath,
|
||||
dexMetadataPath);
|
||||
} catch (Exception e) {
|
||||
throw InstallerException.from(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertValidInstructionSet(String instructionSet)
|
||||
throws InstallerException {
|
||||
for (String abi : Build.SUPPORTED_ABIS) {
|
||||
|
||||
@@ -2425,6 +2425,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
installer, mInstallLock);
|
||||
mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock,
|
||||
dexManagerListener);
|
||||
mArtManagerService = new ArtManagerService(this, installer, mInstallLock);
|
||||
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
|
||||
|
||||
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
|
||||
@@ -3081,7 +3082,6 @@ Slog.e("TODD",
|
||||
}
|
||||
|
||||
mInstallerService = new PackageInstallerService(context, this);
|
||||
mArtManagerService = new ArtManagerService(this, mInstaller, mInstallLock);
|
||||
final Pair<ComponentName, String> instantAppResolverComponent =
|
||||
getInstantAppResolverLPr();
|
||||
if (instantAppResolverComponent != null) {
|
||||
@@ -16901,6 +16901,11 @@ Slog.e("TODD",
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the application profiles for the new code paths.
|
||||
// This needs to be done before invoking dexopt so that any install-time profile
|
||||
// can be used for optimizations.
|
||||
mArtManagerService.prepareAppProfiles(pkg, args.user.getIdentifier());
|
||||
|
||||
// Check whether we need to dexopt the app.
|
||||
//
|
||||
// NOTE: it is IMPORTANT to call dexopt:
|
||||
@@ -21915,6 +21920,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
||||
Slog.e(TAG, "Failed to create app data for " + packageName + ": " + e);
|
||||
}
|
||||
}
|
||||
// Prepare the application profiles.
|
||||
mArtManagerService.prepareAppProfiles(pkg, userId);
|
||||
|
||||
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && ceDataInode != -1) {
|
||||
// TODO: mark this structure as dirty so we persist it!
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
package com.android.server.pm.dex;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.dex.ArtManager;
|
||||
import android.content.pm.dex.DexMetadataHelper;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
@@ -29,10 +33,12 @@ import android.content.pm.IPackageManager;
|
||||
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.pm.Installer;
|
||||
import com.android.server.pm.Installer.InstallerException;
|
||||
@@ -230,4 +236,52 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
|
||||
// Should not happen.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the application profiles.
|
||||
* For all code paths:
|
||||
* - create the current primary profile to save time at app startup time.
|
||||
* - copy the profiles from the associated dex metadata file to the reference profile.
|
||||
*/
|
||||
public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user) {
|
||||
final int appId = UserHandle.getAppId(pkg.applicationInfo.uid);
|
||||
try {
|
||||
ArrayMap<String, String> codePathsProfileNames = getPackageProfileNames(pkg);
|
||||
for (int i = codePathsProfileNames.size() - 1; i >= 0; i--) {
|
||||
String codePath = codePathsProfileNames.keyAt(i);
|
||||
String profileName = codePathsProfileNames.valueAt(i);
|
||||
File dexMetadata = DexMetadataHelper.findDexMetadataForFile(new File(codePath));
|
||||
String dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath();
|
||||
synchronized (mInstaller) {
|
||||
boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId,
|
||||
profileName, codePath, dexMetadataPath);
|
||||
if (!result) {
|
||||
Slog.e(TAG, "Failed to prepare profile for " +
|
||||
pkg.packageName + ":" + codePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InstallerException e) {
|
||||
Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the profiles names for all the package code paths (excluding resource only paths).
|
||||
* Return the map [code path -> profile name].
|
||||
*/
|
||||
private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) {
|
||||
ArrayMap<String, String> result = new ArrayMap<>();
|
||||
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
|
||||
result.put(pkg.baseCodePath, ArtManager.getProfileName(null));
|
||||
}
|
||||
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
|
||||
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
|
||||
if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) {
|
||||
result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user