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

Commit 29d0a836 authored by Nikhil Kumar's avatar Nikhil Kumar Committed by Android (Google) Code Review
Browse files

Merge "Refactor Bug report flow to work for all ADMIN users"

parents 866949a2 4fe5d002
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -455,8 +455,7 @@ public class BugreportProgressService extends Service {
        intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash);
        intent.putExtra(DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_NONCE, nonce);
        intent.putExtra(EXTRA_BUGREPORT, bugreportFileName);
        context.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
                android.Manifest.permission.DUMP);
        context.sendBroadcast(intent, android.Manifest.permission.DUMP);
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -7436,10 +7436,11 @@ public class ActivityManagerService extends IActivityManager.Stub
        if (shareDescription != null) {
            triggerShellBugreport.putExtra(EXTRA_DESCRIPTION, shareDescription);
        }
        UserHandle callingUser = Binder.getCallingUserHandle();
        final long identity = Binder.clearCallingIdentity();
        try {
            // Send broadcast to shell to trigger bugreport using Bugreport API
            mContext.sendBroadcastAsUser(triggerShellBugreport, UserHandle.SYSTEM);
            mContext.sendBroadcastAsUser(triggerShellBugreport, callingUser);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
+14 −22
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.os.IncidentManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;

import com.android.internal.util.DumpUtils;
@@ -128,21 +127,21 @@ public class IncidentCompanionService extends SystemService {
            try {
                final Context context = getContext();

                final int primaryUser = getAndValidateUser(context);
                if (primaryUser == UserHandle.USER_NULL) {
                // Get the current admin user. Only they can do incident reports.
                final int currentAdminUser = getCurrentUserIfAdmin();
                if (currentAdminUser == UserHandle.USER_NULL) {
                    return;
                }

                final Intent intent = new Intent(Intent.ACTION_INCIDENT_REPORT_READY);
                intent.setComponent(new ComponentName(pkg, cls));

                Log.d(TAG, "sendReportReadyBroadcast sending primaryUser=" + primaryUser
                        + " userHandle=" + UserHandle.getUserHandleForUid(primaryUser)
                Log.d(TAG, "sendReportReadyBroadcast sending currentUser=" + currentAdminUser
                        + " userHandle=" + UserHandle.of(currentAdminUser)
                        + " intent=" + intent);

                // Send it to the primary user.  Only they can do incident reports.
                context.sendBroadcastAsUserMultiplePermissions(intent,
                        UserHandle.getUserHandleForUid(primaryUser),
                        UserHandle.of(currentAdminUser),
                        DUMP_AND_USAGE_STATS_PERMISSIONS);
            } finally {
                Binder.restoreCallingIdentity(ident);
@@ -414,10 +413,10 @@ public class IncidentCompanionService extends SystemService {
    }

    /**
     * Check whether the current user is the primary user, and return the user id if they are.
     * Check whether the current user is an admin user, and return the user id if they are.
     * Returns UserHandle.USER_NULL if not valid.
     */
    public static int getAndValidateUser(Context context) {
    public static int getCurrentUserIfAdmin() {
        // Current user
        UserInfo currentUser;
        try {
@@ -427,28 +426,21 @@ public class IncidentCompanionService extends SystemService {
            throw new RuntimeException(ex);
        }

        // Primary user
        final UserManager um = UserManager.get(context);
        final UserInfo primaryUser = um.getPrimaryUser();

        // Check that we're using the right user.
        if (currentUser == null) {
            Log.w(TAG, "No current user.  Nobody to approve the report."
                    + " The report will be denied.");
            return UserHandle.USER_NULL;
        }
        if (primaryUser == null) {
            Log.w(TAG, "No primary user.  Nobody to approve the report."

        if (!currentUser.isAdmin()) {
            Log.w(TAG, "Only an admin user running in foreground can approve "
                    + "bugreports, but the current foreground user is not an admin user. "
                    + "The report will be denied.");
            return UserHandle.USER_NULL;
        }
        if (primaryUser.id != currentUser.id) {
            Log.w(TAG, "Only the primary user can approve bugreports, but they are not"
                    + " the current user. The report will be denied.");
            return UserHandle.USER_NULL;
        }

        return primaryUser.id;
        return currentUser.id;
    }
}
+28 −23
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.incident;

import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.content.ComponentName;
@@ -272,15 +273,19 @@ class PendingReports {
            return;
        }

        // Find the primary user of this device.
        final int primaryUser = getAndValidateUser();
        if (primaryUser == UserHandle.USER_NULL) {
        // Find the current user of the device and check if they are an admin.
        final int currentAdminUser = getCurrentUserIfAdmin();

        // Deny the report if the current admin user is null
        // or not the user who requested the report.
        if (currentAdminUser == UserHandle.USER_NULL
                || currentAdminUser != UserHandle.getUserId(callingUid)) {
            denyReportBeforeAddingRec(listener, callingPackage);
            return;
        }

        // Find the approver app (hint: it's PermissionController).
        final ComponentName receiver = getApproverComponent(primaryUser);
        final ComponentName receiver = getApproverComponent(currentAdminUser);
        if (receiver == null) {
            // We couldn't find an approver... so deny the request here and now, before we
            // do anything else.
@@ -298,26 +303,26 @@ class PendingReports {
        try {
            listener.asBinder().linkToDeath(() -> {
                Log.i(TAG, "Got death notification listener=" + listener);
                cancelReportImpl(listener, receiver, primaryUser);
                cancelReportImpl(listener, receiver, currentAdminUser);
            }, 0);
        } catch (RemoteException ex) {
            Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri());
            // First, remove from our list.
            cancelReportImpl(listener, receiver, primaryUser);
            cancelReportImpl(listener, receiver, currentAdminUser);
        }

        // Go tell Permission controller to start asking the user.
        sendBroadcast(receiver, primaryUser);
        sendBroadcast(receiver, currentAdminUser);
    }

    /**
     * Cancel a pending report request (because of an explicit call to cancel)
     */
    private void cancelReportImpl(IIncidentAuthListener listener) {
        final int primaryUser = getAndValidateUser();
        final ComponentName receiver = getApproverComponent(primaryUser);
        if (primaryUser != UserHandle.USER_NULL && receiver != null) {
            cancelReportImpl(listener, receiver, primaryUser);
        final int currentAdminUser = getCurrentUserIfAdmin();
        final ComponentName receiver = getApproverComponent(currentAdminUser);
        if (currentAdminUser != UserHandle.USER_NULL && receiver != null) {
            cancelReportImpl(listener, receiver, currentAdminUser);
        }
    }

@@ -326,13 +331,13 @@ class PendingReports {
     * by the calling app, or because of a binder death).
     */
    private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver,
            int primaryUser) {
            @UserIdInt int user) {
        // First, remove from our list.
        synchronized (mLock) {
            removePendingReportRecLocked(listener);
        }
        // Second, call back to PermissionController to say it's canceled.
        sendBroadcast(receiver, primaryUser);
        sendBroadcast(receiver, user);
    }

    /**
@@ -342,21 +347,21 @@ class PendingReports {
     * cleanup cases to keep the apps' list in sync with ours.
     */
    private void sendBroadcast() {
        final int primaryUser = getAndValidateUser();
        if (primaryUser == UserHandle.USER_NULL) {
        final int currentAdminUser = getCurrentUserIfAdmin();
        if (currentAdminUser == UserHandle.USER_NULL) {
            return;
        }
        final ComponentName receiver = getApproverComponent(primaryUser);
        final ComponentName receiver = getApproverComponent(currentAdminUser);
        if (receiver == null) {
            return;
        }
        sendBroadcast(receiver, primaryUser);
        sendBroadcast(receiver, currentAdminUser);
    }

    /**
     * Send the confirmation broadcast.
     */
    private void sendBroadcast(ComponentName receiver, int primaryUser) {
    private void sendBroadcast(ComponentName receiver, int currentUser) {
        final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED);
        intent.setComponent(receiver);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -364,8 +369,8 @@ class PendingReports {
        final BroadcastOptions options = BroadcastOptions.makeBasic();
        options.setBackgroundActivityStartsAllowed(true);

        // Send it to the primary user.
        mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser),
        // Send it to the current user.
        mContext.sendBroadcastAsUser(intent, UserHandle.of(currentUser),
                android.Manifest.permission.APPROVE_INCIDENT_REPORTS, options.toBundle());
    }

@@ -420,11 +425,11 @@ class PendingReports {
    }

    /**
     * Check whether the current user is the primary user, and return the user id if they are.
     * Check whether the current user is an admin user, and return the user id if they are.
     * Returns UserHandle.USER_NULL if not valid.
     */
    private int getAndValidateUser() {
        return IncidentCompanionService.getAndValidateUser(mContext);
    private int getCurrentUserIfAdmin() {
        return IncidentCompanionService.getCurrentUserIfAdmin();
    }

    /**
+9 −12
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;

@@ -189,10 +189,10 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
    }

    /**
     * Validates that the current user is the primary user or when bugreport is requested remotely
     * and current user is affiliated user.
     * Validates that the current user is an admin user or, when bugreport is requested remotely
     * that the current user is an affiliated user.
     *
     * @throws IllegalArgumentException if the current user is not the primary user
     * @throws IllegalArgumentException if the current user is not an admin user
     */
    private void ensureUserCanTakeBugReport(int bugreportMode) {
        UserInfo currentUser = null;
@@ -202,20 +202,17 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
            // Impossible to get RemoteException for an in-process call.
        }

        UserInfo primaryUser = UserManager.get(mContext).getPrimaryUser();
        if (currentUser == null) {
            logAndThrow("No current user. Only primary user is allowed to take bugreports.");
            logAndThrow("There is no current user, so no bugreport can be requested.");
        }
        if (primaryUser == null) {
            logAndThrow("No primary user. Only primary user is allowed to take bugreports.");
        }
        if (primaryUser.id != currentUser.id) {

        if (!currentUser.isAdmin()) {
            if (bugreportMode == BugreportParams.BUGREPORT_MODE_REMOTE
                    && isCurrentUserAffiliated(currentUser.id)) {
                return;
            }
            logAndThrow("Current user not primary user. Only primary user"
                    + " is allowed to take bugreports.");
            logAndThrow(TextUtils.formatSimple("Current user %s is not an admin user."
                    + " Only admin users are allowed to take bugreport.", currentUser.id));
        }
    }