Merge "Refactor Bug report flow to work for all ADMIN users"
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 68679c79..6f7d20a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -455,8 +455,7 @@
         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);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e7e2081..6b06bcd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7436,10 +7436,11 @@
         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);
         }
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 87fe785..b8e7d49 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -34,7 +34,6 @@
 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 @@
             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 @@
     }
 
     /**
-     * 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 @@
             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."
-                    + " 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.");
+
+        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;
         }
 
-        return primaryUser.id;
+        return currentUser.id;
     }
 }
 
diff --git a/services/core/java/com/android/server/incident/PendingReports.java b/services/core/java/com/android/server/incident/PendingReports.java
index f39bebf..6285bc3 100644
--- a/services/core/java/com/android/server/incident/PendingReports.java
+++ b/services/core/java/com/android/server/incident/PendingReports.java
@@ -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 @@
             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 @@
         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 @@
      * 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 @@
      * 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 @@
         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 @@
     }
 
     /**
-     * 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();
     }
 
     /**
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 58428ca..2fdc4cd 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -33,8 +33,8 @@
 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 @@
     }
 
     /**
-     * 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 @@
             // 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));
         }
     }