From 4d6f581a97c27412ef1faf935679f86e89779b4d Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Fri, 27 Apr 2018 17:47:24 -0700 Subject: [PATCH] Allow the shell user to snapshot profiles for debuggable apps This is needed in order to be able to CTS test the profile infrastructure via adb shell commands. Test: atest ArtManagerHostTest Bug: 74081010 Change-Id: I116dee2c36d712c0cd067d42994149c734f9edcd --- .../server/pm/dex/ArtManagerService.java | 49 +++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) 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 1d5c5808d705b..0ba78226a38f4 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -34,6 +34,7 @@ import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; @@ -44,6 +45,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; +import com.android.internal.os.RoSystemProperties; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; @@ -106,7 +108,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl()); } - private boolean checkPermission(int callingUid, String callingPackage) { + private boolean checkAndroidPermissions(int callingUid, String callingPackage) { // Callers always need this permission mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_RUNTIME_PROFILES, TAG); @@ -125,11 +127,51 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { } } + /** + * Checks if the calling user is the shell user and if it is, it checks if it can + * to take a profile snapshot of the give package: + * - on debuggable builds the shell user can take profile snapshots of any app. + * - on non-debuggable builds the shell user can only take snapshots of debuggable apps. + * + * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles. + * + * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks. + */ + private boolean checkShellPermissions(@ProfileType int profileType, String packageName, + int callingUid) { + if (callingUid != Process.SHELL_UID) { + return false; + } + if (RoSystemProperties.DEBUGGABLE) { + return true; + } + if (profileType == ArtManager.PROFILE_BOOT_IMAGE) { + // The shell cannot profile the boot image on non-debuggable builds. + return false; + } + PackageInfo info = null; + try { + info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0); + } catch (RemoteException ignored) { + // Should not happen. + } + if (info == null) { + return false; + } + + // On user builds the shell can only profile debuggable apps. + return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) + == ApplicationInfo.FLAG_DEBUGGABLE; + } + + @Override public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName, @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback, String callingPackage) { - if (!checkPermission(Binder.getCallingUid(), callingPackage)) { + int callingUid = Binder.getCallingUid(); + if (!checkShellPermissions(profileType, packageName, callingUid) && + !checkAndroidPermissions(callingUid, callingPackage)) { try { callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); } catch (RemoteException ignored) { @@ -266,7 +308,8 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { @Override public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) { - if (!checkPermission(Binder.getCallingUid(), callingPackage)) { + int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) { return false; }