OSDN Git Service

[framework] Extend profile operations to take the profile name
authorCalin Juravle <calin@google.com>
Sat, 20 Jan 2018 04:32:47 +0000 (20:32 -0800)
committerCalin Juravle <calin@google.com>
Wed, 24 Jan 2018 22:56:38 +0000 (14:56 -0800)
Extend the installd profile interface to take the profile name as
argument. This shifts the responsibility for choosing the names of
profiles for primary apks completely to PackageManager. Each of the
application code paths will get an unique profile name based on their
split name.

All the profile operations will now work on a specific profile name rather
than assuming a default global name.

Also, move dumpProfiles and clearProfiles functionality to the
ArtManagerService so that we can re-use profileName computations easier.

Test: manual (dexopt apps, merge profiles, clear profiles)
      gts GtsAndroidRuntimeManagerHostTestCases
Bug: 30934496

Change-Id: Ie65d45eed7de0844edf4b7af918d7eaa74ec1f2c

core/java/android/app/LoadedApk.java
core/java/android/content/pm/dex/ArtManager.java
core/java/android/os/Environment.java
core/java/com/android/internal/os/ZygoteInit.java
services/core/java/com/android/server/pm/Installer.java
services/core/java/com/android/server/pm/OtaDexoptService.java
services/core/java/com/android/server/pm/PackageDexOptimizer.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/dex/ArtManagerService.java

index 26f4980..d24d4f3 100644 (file)
@@ -28,6 +28,7 @@ import android.content.pm.ApplicationInfo;
 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;
@@ -35,7 +36,6 @@ import android.content.res.Configuration;
 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;
@@ -49,13 +49,15 @@ import android.text.TextUtils;
 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;
@@ -749,13 +751,6 @@ public final class LoadedApk {
         }
     }
 
-    // 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;
@@ -783,10 +778,12 @@ public final class LoadedApk {
             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
index aa9c46e..f979576 100644 (file)
@@ -19,6 +19,7 @@ package android.content.pm.dex;
 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;
@@ -26,6 +27,8 @@ import android.os.ParcelFileDescriptor;
 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.
@@ -163,4 +166,29 @@ public class ArtManager {
     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);
+
+    }
 }
index 62731e8..158041d 100644 (file)
@@ -302,9 +302,8 @@ public class Environment {
     }
 
     /** {@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} */
index 5659470..39279b5 100644 (file)
@@ -583,7 +583,7 @@ public class ZygoteInit {
                     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: "
index cdc79c7..2e9ab0b 100644 (file)
@@ -286,43 +286,44 @@ public class Installer extends SystemService {
     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);
         }
@@ -366,10 +367,10 @@ public class Installer extends SystemService {
         }
     }
 
-    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);
         }
@@ -502,21 +503,21 @@ public class Installer extends SystemService {
         }
     }
 
-    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);
         }
index 0395011..5bf38dc 100644 (file)
@@ -261,12 +261,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                     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");
 
@@ -283,6 +283,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                 encodeParameter(builder, seInfo);
                 encodeParameter(builder, downgrade);
                 encodeParameter(builder, targetSdkVersion);
+                encodeParameter(builder, profileName);
 
                 commands.add(builder.toString());
             }
index 6a08e1b..8c18511 100644 (file)
@@ -20,6 +20,7 @@ import android.annotation.Nullable;
 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;
@@ -211,12 +212,14 @@ public class PackageDexOptimizer {
                 }
             }
 
+            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.
@@ -225,7 +228,7 @@ public class PackageDexOptimizer {
             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,
@@ -249,7 +252,8 @@ public class PackageDexOptimizer {
     @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) {
@@ -275,7 +279,8 @@ public class PackageDexOptimizer {
             // 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();
@@ -396,7 +401,7 @@ public class PackageDexOptimizer {
                 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;
@@ -550,14 +555,15 @@ public class PackageDexOptimizer {
      * 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);
         }
index 299c59a..9fdbdbe 100644 (file)
@@ -195,6 +195,7 @@ import android.content.pm.UserInfo;
 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;
@@ -8873,7 +8874,8 @@ Slog.e("TODD",
                         // 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
@@ -8908,7 +8910,8 @@ Slog.e("TODD",
                                 // 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;
@@ -9333,14 +9336,7 @@ Slog.e("TODD",
 
         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);
         }
     }
@@ -9416,6 +9412,8 @@ Slog.e("TODD",
         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) {
@@ -9488,18 +9486,10 @@ Slog.e("TODD",
             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));
         }
     }
 
@@ -16108,7 +16098,6 @@ Slog.e("TODD",
 
             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,
@@ -16247,7 +16236,6 @@ Slog.e("TODD",
         // 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,
@@ -20283,7 +20271,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                     }
                     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);
                 }
index 8178689..f15dc2d 100644 (file)
@@ -25,7 +25,6 @@ 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;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -111,11 +110,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
         }
 
         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;
                 }
             }
@@ -126,18 +127,18 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
         }
 
         // 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;
                 }
@@ -148,28 +149,30 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
         }
 
         // 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);
             }
         }
     }
@@ -284,6 +287,40 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
     }
 
     /**
+     * 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].
      */