Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d6f581a authored by Calin Juravle's avatar Calin Juravle
Browse files

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
parent d5060280
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -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;
        }