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

Commit 5d82a5e2 authored by Chris Baron's avatar Chris Baron
Browse files

Allow callers with automotive projection role to call startBugreport().

See go/delayed-bugreport-retrieval-v2 for full context. The delayed bugreport retrieval API was added for Android Auto, but Android Auto does not have access to use it without this change.

BYPASS_INCLUSIVE_LANGUAGE_REASON=The name of the config field cannot be changed.

Bug: 289532159
Test: Treehugger passes and tested on phone
Change-Id: I2b612b367650f0e1f9ddef4e6c95da4540a12149
(cherry picked from commit 9e995a57)
parent 7591b03d
Loading
Loading
Loading
Loading
+19 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -64,6 +65,8 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
    private static final int LOCAL_LOG_SIZE = 20;
    private static final String TAG = "BugreportManagerService";
    private static final boolean DEBUG = false;
    private static final String ROLE_SYSTEM_AUTOMOTIVE_PROJECTION =
            "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION";

    private static final String BUGREPORT_SERVICE = "bugreportd";
    private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
@@ -326,11 +329,22 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {

        // To gain access through the DUMP permission, the OEM has to allow this package explicitly
        // via sysconfig and privileged permissions.
        if (mBugreportAllowlistedPackages.contains(callingPackage)
                && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                        == PackageManager.PERMISSION_GRANTED) {
        boolean allowlisted = mBugreportAllowlistedPackages.contains(callingPackage);
        if (!allowlisted) {
            final long token = Binder.clearCallingIdentity();
            try {
                allowlisted = mContext.getSystemService(RoleManager.class).getRoleHolders(
                        ROLE_SYSTEM_AUTOMOTIVE_PROJECTION).contains(callingPackage);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        if (allowlisted && mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.DUMP) == PackageManager.PERMISSION_GRANTED) {
            return;
        }

        // For carrier privileges, this can include user-installed apps. This is essentially a
        // function of the current active SIM(s) in the device to let carrier apps through.
        final long token = Binder.clearCallingIdentity();
@@ -346,7 +360,8 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {

        String message =
                callingPackage
                        + " does not hold the DUMP permission or is not bugreport-whitelisted "
                        + " does not hold the DUMP permission or is not bugreport-whitelisted or "
                        + "does not have an allowed role "
                        + (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
                        + "to request a bugreport";
        Slog.w(TAG, message);
+1 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@
    <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
    <uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
    <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" />

    <queries>
        <package android:name="com.android.servicestests.apps.suspendtestapp" />
+50 −7
Original line number Diff line number Diff line
@@ -16,15 +16,18 @@

package com.android.server.os;

import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertThrows;

import android.app.role.RoleManager;
import android.content.Context;
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
import android.os.IBinder;
import android.os.IDumpstateListener;
import android.os.Process;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Pair;
@@ -37,21 +40,23 @@ import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.FileDescriptor;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

@RunWith(AndroidJUnit4.class)
public class BugreportManagerServiceImplTest {

    Context mContext;
    BugreportManagerServiceImpl mService;
    BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
    private Context mContext;
    private BugreportManagerServiceImpl mService;
    private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;

    int mCallingUid = 1234;
    String mCallingPackage  = "test.package";
    private int mCallingUid = 1234;
    private String mCallingPackage  = "test.package";

    String mBugreportFile = "bugreport-file.zip";
    String mBugreportFile2 = "bugreport-file2.zip";
    private String mBugreportFile = "bugreport-file.zip";
    private String mBugreportFile2 = "bugreport-file2.zip";

    @Before
    public void setUp() {
@@ -109,6 +114,36 @@ public class BugreportManagerServiceImplTest {
                BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
    }

    @Test
    public void testCancelBugreportWithoutRole() throws Exception {
        // Clear out allowlisted packages.
        mService = new BugreportManagerServiceImpl(
                new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));

        assertThrows(SecurityException.class, () -> mService.cancelBugreport(
                Binder.getCallingUid(), mContext.getPackageName()));
    }

    @Test
    public void testCancelBugreportWithRole() throws Exception {
        // Clear out allowlisted packages.
        mService = new BugreportManagerServiceImpl(
                new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
        CallbackFuture future = new CallbackFuture();
        runWithShellPermissionIdentity(() -> roleManager.setBypassingRoleQualification(true));
        runWithShellPermissionIdentity(() -> roleManager.addRoleHolderAsUser(
                "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
                mContext.getPackageName(),
                /* flags= */ 0,
                Process.myUserHandle(),
                mContext.getMainExecutor(),
                future));

        assertThat(future.get()).isEqualTo(true);
        mService.cancelBugreport(Binder.getCallingUid(), mContext.getPackageName());
    }

    private static class Listener implements IDumpstateListener {
        CountDownLatch mLatch;
        int mErrorCode;
@@ -149,4 +184,12 @@ public class BugreportManagerServiceImplTest {
            return mErrorCode;
        }
    }

    private static class CallbackFuture extends CompletableFuture<Boolean>
            implements Consumer<Boolean> {
        @Override
        public void accept(Boolean successful) {
            complete(successful);
        }
    }
}