import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.dex.ArtManager;
import android.content.pm.split.SplitDependencyLoader;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.LogPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;
+
import com.android.internal.util.ArrayUtils;
+
import dalvik.system.VMRuntime;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
}
}
- // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
- private static File getPrimaryProfileFile(String packageName) {
- File profileDir = Environment.getDataProfilesDePackageDirectory(
- UserHandle.myUserId(), packageName);
- return new File(profileDir, "primary.prof");
- }
-
private void setupJitProfileSupport() {
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
return;
}
- final File profileFile = getPrimaryProfileFile(mPackageName);
-
- VMRuntime.registerAppInfo(profileFile.getPath(),
- codePaths.toArray(new String[codePaths.size()]));
+ for (int i = codePaths.size() - 1; i >= 0; i--) {
+ String splitName = i == 0 ? null : mApplicationInfo.splitNames[i - 1];
+ String profileFile = ArtManager.getCurrentProfilePath(
+ mPackageName, UserHandle.myUserId(), splitName);
+ VMRuntime.registerAppInfo(profileFile, new String[] {codePaths.get(i)});
+ }
// Register the app data directory with the reporter. It will
// help deciding whether or not a dex file is the primary apk or a
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
+import java.io.File;
+
/**
* Class for retrieving various kinds of information related to the runtime artifacts of
* packages that are currently installed on the device.
public static String getProfileName(String splitName) {
return splitName == null ? "primary.prof" : splitName + ".split.prof";
}
+
+ /**
+ * Return the path to the current profile corresponding to given package and split.
+ *
+ * @hide
+ */
+ public static String getCurrentProfilePath(String packageName, int userId, String splitName) {
+ File profileDir = Environment.getDataProfilesDePackageDirectory(userId, packageName);
+ return new File(profileDir, getProfileName(splitName)).getAbsolutePath();
+ }
+
+ /**
+ * Return the snapshot profile file for the given package and split.
+ *
+ * KEEP in sync with installd dexopt.cpp.
+ * TODO(calin): inject the snapshot profile name from PM to avoid the dependency.
+ *
+ * @hide
+ */
+ public static File getProfileSnapshotFile(String packageName, String splitName) {
+ File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName);
+ String snapshotFile = getProfileName(splitName) + ".snapshot";
+ return new File(profileDir, snapshotFile);
+
+ }
}
}
/** {@hide} */
- public static File getProfileSnapshotPath(String packageName, String codePath) {
- return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName,
- "primary.prof.snapshot"));
+ public static File getDataRefProfilesDePackageDirectory(String packageName) {
+ return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
}
/** {@hide} */
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion);
+ targetSdkVersion, /*profileName*/ null);
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
- @Nullable String seInfo, boolean downgrade, int targetSdkVersion)
- throws InstallerException {
+ @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
+ @Nullable String profileName) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion);
+ targetSdkVersion, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
+ public boolean mergeProfiles(int uid, String packageName, String profileName)
+ throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.mergeProfiles(uid, packageName);
+ return mInstalld.mergeProfiles(uid, packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public boolean dumpProfiles(int uid, String packageName, String codePaths)
+ public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath)
throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.dumpProfiles(uid, packageName, codePaths);
+ return mInstalld.dumpProfiles(uid, packageName, profileName, codePath);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public boolean copySystemProfile(String systemProfile, int uid, String packageName)
- throws InstallerException {
+ public boolean copySystemProfile(String systemProfile, int uid, String packageName,
+ String profileName) throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.copySystemProfile(systemProfile, uid, packageName);
+ return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
}
- public void clearAppProfiles(String packageName) throws InstallerException {
+ public void clearAppProfiles(String packageName, String profileName) throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.clearAppProfiles(packageName);
+ mInstalld.clearAppProfiles(packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
}
- public boolean createProfileSnapshot(int appId, String packageName, String codePath)
+ public boolean createProfileSnapshot(int appId, String packageName, String profileName)
throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.createProfileSnapshot(appId, packageName, codePath);
+ return mInstalld.createProfileSnapshot(appId, packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public void destroyProfileSnapshot(String packageName, String codePath)
+ public void destroyProfileSnapshot(String packageName, String profileName)
throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.destroyProfileSnapshot(packageName, codePath);
+ mInstalld.destroyProfileSnapshot(packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
String instructionSet, int dexoptNeeded, @Nullable String outputPath,
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
- int targetSdkVersion)
+ int targetSdkVersion, @Nullable String profileName)
throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 4.
- builder.append("4 ");
+ // The version. Right now it's 5.
+ builder.append("5 ");
builder.append("dexopt");
encodeParameter(builder, seInfo);
encodeParameter(builder, downgrade);
encodeParameter(builder, targetSdkVersion);
+ encodeParameter(builder, profileName);
commands.add(builder.toString());
}
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
+import android.content.pm.dex.ArtManager;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
}
}
+ String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|| packageUseInfo.isUsedByOtherApps(path);
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
options.getCompilerFilter(), isUsedByOtherApps);
final boolean profileUpdated = options.isCheckForProfileUpdates() &&
- isProfileUpdated(pkg, sharedGid, compilerFilter);
+ isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
// flags.
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade());
+ packageStats, options.isDowngrade(), profileName);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@GuardedBy("mInstallLock")
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
- int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) {
+ int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
+ String profileName) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
// primary dex files.
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
- false /* downgrade*/, pkg.applicationInfo.targetSdkVersion);
+ false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+ profileName);
if (packageStats != null) {
long endTime = System.currentTimeMillis();
mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
- options.isDowngrade(), info.targetSdkVersion);
+ options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null);
}
return DEX_OPT_PERFORMED;
* current profile and the reference profile will be merged and subsequent calls
* may return a different result.
*/
- private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter) {
+ private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+ String compilerFilter) {
// Check if we are allowed to merge and if the compiler filter is profile guided.
if (!isProfileGuidedCompilerFilter(compilerFilter)) {
return false;
}
// Merge profiles. It returns whether or not there was an updated in the profile info.
try {
- return mInstaller.mergeProfiles(uid, pkg.packageName);
+ return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to merge profiles", e);
}
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.res.Resources;
// PackageDexOptimizer to prevent this happening on first boot. The issue
// is that we don't have a good way to say "do this only once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
// Disabled as this causes speed-profile compilation during first boot
// issue is that we don't have a good way to say "do this only
// once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Failed to copy system profile for stub package!");
} else {
useProfileForDexopt = true;
synchronized (mInstallLock) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- try {
- List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly();
- String codePaths = TextUtils.join(";", allCodePaths);
- mInstaller.dumpProfiles(sharedGid, packageName, codePaths);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dump profiles", e);
- }
+ mArtManagerService.dumpProfiles(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
for (int i = 0; i < childCount; i++) {
clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
+
+ clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
- clearAppProfilesLeafLIF(pkg);
+ mArtManagerService.clearAppProfiles(pkg);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
- clearAppProfilesLeafLIF(pkg.childPackages.get(i));
- }
- }
-
- private void clearAppProfilesLeafLIF(PackageParser.Package pkg) {
- try {
- mInstaller.clearAppProfiles(pkg.packageName);
- } catch (InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
+ mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
}
}
clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
// Successfully disabled the old package. Now proceed with re-installation
clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
}
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
| FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
mDexManager.notifyPackageUpdated(pkg.packageName,
pkg.baseCodePath, pkg.splitCodePaths);
}
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.os.Binder;
-import android.os.Environment;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
}
boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
+ String splitName = null;
String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
if (!pathFound && (splitCodePaths != null)) {
- for (String path : splitCodePaths) {
- if (path.equals(codePath)) {
+ for (int i = splitCodePaths.length - 1; i >= 0; i--) {
+ if (splitCodePaths[i].equals(codePath)) {
pathFound = true;
+ splitName = info.applicationInfo.splitNames[i];
break;
}
}
}
// All good, create the profile snapshot.
- createProfileSnapshot(packageName, codePath, callback, info);
+ createProfileSnapshot(packageName, splitName, callback, info);
// Destroy the snapshot, we no longer need it.
- destroyProfileSnapshot(packageName, codePath);
+ destroyProfileSnapshot(packageName, splitName);
}
- private void createProfileSnapshot(String packageName, String codePath,
+ private void createProfileSnapshot(String packageName, String splitName,
ISnapshotRuntimeProfileCallback callback, PackageInfo info) {
// Ask the installer to snapshot the profile.
synchronized (mInstallLock) {
try {
if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid),
- packageName, codePath)) {
+ packageName, ArtManager.getProfileName(splitName))) {
postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
return;
}
}
// Open the snapshot and invoke the callback.
- File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath);
+ File snapshotProfile = ArtManager.getProfileSnapshotFile(packageName, splitName);
ParcelFileDescriptor fd;
try {
fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
postSuccess(packageName, fd, callback);
} catch (FileNotFoundException e) {
- Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + codePath, e);
+ Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
+ + snapshotProfile, e);
postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
}
}
- private void destroyProfileSnapshot(String packageName, String codePath) {
+ private void destroyProfileSnapshot(String packageName, String splitName) {
if (DEBUG) {
- Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath);
+ Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + splitName);
}
synchronized (mInstallLock) {
try {
- mInstaller.destroyProfileSnapshot(packageName, codePath);
+ mInstaller.destroyProfileSnapshot(packageName,
+ ArtManager.getProfileName(splitName));
} catch (InstallerException e) {
Slog.e(TAG, "Failed to destroy profile snapshot for " +
- packageName + ":" + codePath, e);
+ packageName + ":" + splitName, e);
}
}
}
}
/**
+ * Clear the profiles for the given package.
+ */
+ public void clearAppProfiles(PackageParser.Package pkg) {
+ try {
+ ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+ for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+ String profileName = packageProfileNames.valueAt(i);
+ mInstaller.clearAppProfiles(pkg.packageName, profileName);
+ }
+ } catch (InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ }
+
+ /**
+ * Dumps the profiles for the given package.
+ */
+ public void dumpProfiles(PackageParser.Package pkg) {
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ try {
+ ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+ for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+ String codePath = packageProfileNames.keyAt(i);
+ String profileName = packageProfileNames.valueAt(i);
+ synchronized (mInstallLock) {
+ mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+ }
+ }
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dump profiles", e);
+ }
+ }
+
+ /**
* Build the profiles names for all the package code paths (excluding resource only paths).
* Return the map [code path -> profile name].
*/