summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nikhil Kumar <nykkumar@google.com> 2022-12-01 18:13:42 +0000
committer Nikhil Kumar <nykkumar@google.com> 2022-12-06 17:16:41 +0000
commit4fe5d002a2e5bf342ae4ee10e780ff62aa713cf4 (patch)
treebef513364ebd0c4106ccc159f692cc4994a05ac1
parentcb699221b183e37e679b766fa78e8377f5cfef92 (diff)
Refactor Bug report flow to work for all ADMIN users
With the existing implementation only the primary user is allowed to take bug report and approve authorization for bug and inicdent reports to be taken. With hsum (Headlesss SYSTEM user mode) implementation primary user will always run in background. we need to refactor the bugreport flow so that it can be triggered by any admin user. The following components has been refactored to allow any ADMIN user to trigger the bugreport, see progress notification, pass user inputs in case of interactive bugreport and share the bugreport. Though the actual bugreport (dumpstate) will always run on user 0 only the user visible components and components responsible to trigger the bugreport and track progress ex- shell, any approved bundled app like betterbug will run on the current foreground admin user. 1. ActivityManagerService.requestBugReportWithDescription has been modified to send BUGREPORT_REQUESTED broadcast to the caller user. 2. BugReportManagerServiceImpl has been modified to enable any admin user to initiate the bug report. 3. BugReportProgressService has been modified to send BUGREPORT_FINISHED broadcast to the shell context user. 4. IncidentCompanionService and PendingReports has been modifed to let any admin user provide feedback and authorization for bug and inicdent reports to be taken. Bug: 256583570 Test: atest BugreportManagerTest Test: Manually tested that admin users are allowed to take bug report. Change-Id: Ib22775e7ad998369404cf15cdc220c9b4019b296
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/incident/IncidentCompanionService.java36
-rw-r--r--services/core/java/com/android/server/incident/PendingReports.java51
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java21
5 files changed, 54 insertions, 60 deletions
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 68679c794c35..6f7d20a950d5 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -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);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2761a864f22f..453b6df797c5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7391,10 +7391,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);
}
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 87fe785ca614..b8e7d4971790 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.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."
- + " 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 f39bebf060f7..6285bc3f531b 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 @@ 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();
}
/**
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 58428ca48c97..2fdc4cd5f7c1 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.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));
}
}