From 369fbd29838a98aed84bff16af415da574df9576 Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Wed, 29 Nov 2017 18:26:55 -0800 Subject: [PATCH] Implement ArtManager#snapshotProfile API Complete the implementation of ArtManager#snapshotProfile. The snapshot is performed by calling the installer and then return to the caller via the specified callback. (cherry picked from commit fd9f8ae973122a50f336e38c386ecbc0095d8adc) Bug: 30934496 Test: gts-tradefed -m GtsAndroidRuntimeManagerHostTestCases Merged-In: I87131487846d91d79a56041445420376b61ca8e7 Change-Id: I87131487846d91d79a56041445420376b61ca8e7 --- core/java/android/os/Environment.java | 5 +- .../java/com/android/server/pm/Installer.java | 20 +++++ .../server/pm/PackageManagerService.java | 2 +- .../server/pm/dex/ArtManagerService.java | 84 ++++++++++++++++++- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 5b0e5bbce2f76..3175750a632fe 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -291,8 +291,9 @@ public class Environment { } /** {@hide} */ - public static File getReferenceProfile(String packageName) { - return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName); + public static File getProfileSnapshotPath(String packageName, String codePath) { + return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName, + "primary.prof.snapshot")); } /** {@hide} */ diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 90d9bb7475d19..653bb950ec891 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -499,6 +499,26 @@ public class Installer extends SystemService { } } + public boolean createProfileSnapshot(int appId, String packageName, String codePath) + throws InstallerException { + if (!checkBeforeRemote()) return false; + try { + return mInstalld.snapshotProfile(appId, packageName, codePath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + + public void destroyProfileSnapshot(String packageName, String codePath) + throws InstallerException { + if (!checkBeforeRemote()) return; + try { + mInstalld.destroyProfileSnapshot(packageName, codePath); + } catch (Exception e) { + throw InstallerException.from(e); + } + } + public void invalidateMounts() throws InstallerException { if (!checkBeforeRemote()) return; try { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 92e4f9914b865..d89edbffac4f5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3064,7 +3064,7 @@ public class PackageManagerService extends IPackageManager.Stub } mInstallerService = new PackageInstallerService(context, this); - mArtManagerService = new ArtManagerService(this); + mArtManagerService = new ArtManagerService(this, mInstaller, mInstallLock); final Pair instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index 5a1f840e945b2..2dbb34d888e5f 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -21,15 +21,23 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.dex.ArtManager; import android.os.Binder; +import android.os.Environment; import android.os.Handler; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.content.pm.IPackageManager; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; import com.android.internal.util.Preconditions; +import com.android.server.pm.Installer; +import com.android.server.pm.Installer.InstallerException; +import java.io.File; +import java.io.FileNotFoundException; /** * A system service that provides access to runtime and compiler artifacts. @@ -50,10 +58,16 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { private static boolean DEBUG_IGNORE_PERMISSIONS = false; private final IPackageManager mPackageManager; + private final Object mInstallLock; + @GuardedBy("mInstallLock") + private final Installer mInstaller; + private final Handler mHandler; - public ArtManagerService(IPackageManager pm) { + public ArtManagerService(IPackageManager pm, Installer installer, Object installLock) { mPackageManager = pm; + mInstaller = installer; + mInstallLock = installLock; mHandler = new Handler(BackgroundThread.getHandler().getLooper()); } @@ -105,8 +119,53 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { return; } - // All good, move forward and get the profile. - postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + // All good, create the profile snapshot. + createProfileSnapshot(packageName, codePath, callback, info); + // Destroy the snapshot, we no longer need it. + destroyProfileSnapshot(packageName, codePath); + } + + private void createProfileSnapshot(String packageName, String codePath, + ISnapshotRuntimeProfileCallback callback, PackageInfo info) { + // Ask the installer to snapshot the profile. + synchronized (mInstallLock) { + try { + if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid), + packageName, codePath)) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } catch (InstallerException e) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + return; + } + } + + // Open the snapshot and invoke the callback. + File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath); + 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); + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + } + } + + private void destroyProfileSnapshot(String packageName, String codePath) { + if (DEBUG) { + Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath); + } + + synchronized (mInstallLock) { + try { + mInstaller.destroyProfileSnapshot(packageName, codePath); + } catch (InstallerException e) { + Slog.e(TAG, "Failed to destroy profile snapshot for " + + packageName + ":" + codePath, e); + } + } } @Override @@ -123,6 +182,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { */ private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, int errCode) { + if (DEBUG) { + Slog.d(TAG, "Failed to snapshot profile for " + packageName + " with error: " + + errCode); + } mHandler.post(() -> { try { callback.onError(errCode); @@ -132,6 +195,21 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { }); } + private void postSuccess(String packageName, ParcelFileDescriptor fd, + ISnapshotRuntimeProfileCallback callback) { + if (DEBUG) { + Slog.d(TAG, "Successfully snapshot profile for " + packageName); + } + mHandler.post(() -> { + try { + callback.onSuccess(fd); + } catch (RemoteException e) { + Slog.w(TAG, + "Failed to call onSuccess after profile snapshot for " + packageName, e); + } + }); + } + /** * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. * If not, it throws a {@link SecurityException}.