summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorJoe Onorato <joeo@google.com>2019-01-29 19:34:40 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2019-01-29 19:34:40 +0000
commit917955a4e669c9b237db621359ed67117758605a (patch)
tree2a7bb4adc7767442dc2ba136a654019c3b03111f /core/java/android
parentafe6ec4b271890b3ea943c1208acd6282642ee9b (diff)
parente21ab7eab46d1c99e0e3e3506edaca096f796e2d (diff)
Merge changes from topic "bug and incident report approval"
* changes: Add IncidentCompanionService Added a new "incidentReportApprover" permission protection flag.
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ApplicationPackageManager.java9
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/Intent.java12
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java13
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java2
-rw-r--r--core/java/android/content/pm/PermissionInfo.java14
-rw-r--r--core/java/android/os/IncidentManager.java317
8 files changed, 361 insertions, 16 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 4491b95f968a..a93742273306 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3026,6 +3026,15 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public String getIncidentReportApproverPackageName() {
+ try {
+ return mPM.getIncidentReportApproverPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public boolean isPackageStateProtected(String packageName, int userId) {
try {
return mPM.isPackageStateProtected(packageName, userId);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 87f9e464cdc2..d9d0ee98e5ac 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3180,6 +3180,7 @@ public abstract class Context {
//@hide: CONTEXTHUB_SERVICE,
SYSTEM_HEALTH_SERVICE,
//@hide: INCIDENT_SERVICE,
+ //@hide: INCIDENT_COMPANION_SERVICE,
//@hide: STATS_COMPANION_SERVICE,
COMPANION_DEVICE_SERVICE,
CROSS_PROFILE_APPS_SERVICE,
@@ -4466,6 +4467,13 @@ public abstract class Context {
public static final String INCIDENT_SERVICE = "incident";
/**
+ * Service to assist incidentd and dumpstated in reporting status to the user
+ * and in confirming authorization to take an incident report or bugreport
+ * @hide
+ */
+ public static final String INCIDENT_COMPANION_SERVICE = "incidentcompanion";
+
+ /**
* Service to assist statsd in obtaining general stats.
* @hide
*/
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 22f73dbd4644..8d14091478c3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1475,6 +1475,18 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
/**
+ * An incident or bug report has been taken, and a system app has requested it to be shared,
+ * so trigger the confirmation screen.
+ *
+ * This will be sent directly to the registered receiver with the
+ * android.permission.APPROVE_INCIDENT_REPORTS permission.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED =
+ "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED";
+
+ /**
* Activity Action: Show power usage information to the user.
* <p>Input: Nothing.
* <p>Output: Nothing.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7bd8c4e244c7..a6a6f013839a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -688,6 +688,8 @@ interface IPackageManager {
String getContentCaptureServicePackageName();
+ String getIncidentReportApproverPackageName();
+
boolean isPackageStateProtected(String packageName, int userId);
void sendDeviceCustomizationReadyBroadcast();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0aa33c89f2de..3a675c901a9f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -6744,6 +6744,19 @@ public abstract class PackageManager {
}
/**
+ * @return the incident report approver app package name, or null if it's not defined
+ * by the OEM.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public String getIncidentReportApproverPackageName() {
+ throw new UnsupportedOperationException(
+ "getIncidentReportApproverPackageName not implemented in subclass");
+ }
+
+ /**
* @return whether a given package's state is protected, e.g. package cannot be disabled,
* suspended, hidden or force stopped.
*
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index c9a4c8270390..738730ec3f51 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -56,6 +56,7 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_WELLBEING = 7;
public static final int PACKAGE_DOCUMENTER = 8;
public static final int PACKAGE_CONFIGURATOR = 9;
+ public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 10;
@IntDef(value = {
PACKAGE_SYSTEM,
PACKAGE_SETUP_WIZARD,
@@ -67,6 +68,7 @@ public abstract class PackageManagerInternal {
PACKAGE_WELLBEING,
PACKAGE_DOCUMENTER,
PACKAGE_CONFIGURATOR,
+ PACKAGE_INCIDENT_REPORT_APPROVER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 5d2cf0a7d101..e7769849ccc3 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -213,6 +213,16 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@TestApi
public static final int PROTECTION_FLAG_CONFIGURATOR = 0x80000;
+ /**
+ * Additional flag for {${link #protectionLevel}, corresponding
+ * to the <code>incident_report_approver</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 0x100000;
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
@@ -233,6 +243,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
PROTECTION_FLAG_WELLBEING,
PROTECTION_FLAG_DOCUMENTER,
PROTECTION_FLAG_CONFIGURATOR,
+ PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -431,6 +442,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PROTECTION_FLAG_CONFIGURATOR) != 0) {
protLevel += "|configurator";
}
+ if ((level & PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER) != 0) {
+ protLevel += "|incidentReportApprover";
+ }
return protLevel;
}
diff --git a/core/java/android/os/IncidentManager.java b/core/java/android/os/IncidentManager.java
index 0e6652d471a5..88a578a5b6de 100644
--- a/core/java/android/os/IncidentManager.java
+++ b/core/java/android/os/IncidentManager.java
@@ -16,13 +16,18 @@
package android.os;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
+import android.net.Uri;
import android.util.Slog;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Class to take an incident report.
*
@@ -34,9 +39,200 @@ import android.util.Slog;
public class IncidentManager {
private static final String TAG = "IncidentManager";
+ /**
+ * Authority for pending report id urls.
+ *
+ * @hide
+ */
+ public static final String URI_SCHEME = "content";
+
+ /**
+ * Authority for pending report id urls.
+ *
+ * @hide
+ */
+ public static final String URI_AUTHORITY = "android.os.IncidentManager";
+
+ /**
+ * Authority for pending report id urls.
+ *
+ * @hide
+ */
+ public static final String URI_PATH = "/pending";
+
+ /**
+ * Query parameter for the uris for the pending report id.
+ *
+ * @hide
+ */
+ public static final String URI_PARAM_ID = "id";
+
+ /**
+ * Query parameter for the uris for the pending report id.
+ *
+ * @hide
+ */
+ public static final String URI_PARAM_CALLING_PACKAGE = "pkg";
+
+ /**
+ * Query parameter for the uris for the pending report id, in wall clock
+ * ({@link System.currentTimeMillis()}) timebase.
+ *
+ * @hide
+ */
+ public static final String URI_PARAM_TIMESTAMP = "t";
+
+ /**
+ * Query parameter for the uris for the pending report id.
+ *
+ * @hide
+ */
+ public static final String URI_PARAM_FLAGS = "flags";
+
+ /**
+ * Do the confirmation with a dialog instead of the default, which is a notification.
+ * It is possible for the dialog to be downgraded to a notification in some cases.
+ */
+ public static final int FLAG_CONFIRMATION_DIALOG = 0x1;
+
private final Context mContext;
- private IIncidentManager mService;
+ private Object mLock = new Object();
+ private IIncidentManager mIncidentService;
+ private IIncidentCompanion mCompanionService;
+
+ /**
+ * Record for a report that has been taken and is pending user authorization
+ * to share it.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static class PendingReport {
+ /**
+ * Encoded data.
+ */
+ private final Uri mUri;
+
+ /**
+ * URI_PARAM_FLAGS from the uri
+ */
+ private final int mFlags;
+
+ /**
+ * URI_PARAM_CALLING_PACKAGE from the uri
+ */
+ private final String mRequestingPackage;
+
+ /**
+ * URI_PARAM_TIMESTAMP from the uri
+ */
+ private final long mTimestamp;
+
+ /**
+ * Constructor.
+ */
+ public PendingReport(@NonNull Uri uri) {
+ int flags = 0;
+ try {
+ flags = Integer.parseInt(uri.getQueryParameter(URI_PARAM_FLAGS));
+ } catch (NumberFormatException ex) {
+ throw new RuntimeException("Invalid URI: No " + URI_PARAM_FLAGS
+ + " parameter. " + uri);
+ }
+ mFlags = flags;
+
+ String requestingPackage = uri.getQueryParameter(URI_PARAM_CALLING_PACKAGE);
+ if (requestingPackage == null) {
+ throw new RuntimeException("Invalid URI: No " + URI_PARAM_CALLING_PACKAGE
+ + " parameter. " + uri);
+ }
+ mRequestingPackage = requestingPackage;
+
+ long timestamp = -1;
+ try {
+ timestamp = Long.parseLong(uri.getQueryParameter(URI_PARAM_TIMESTAMP));
+ } catch (NumberFormatException ex) {
+ throw new RuntimeException("Invalid URI: No " + URI_PARAM_TIMESTAMP
+ + " parameter. " + uri);
+ }
+ mTimestamp = timestamp;
+
+ mUri = uri;
+ }
+
+ /**
+ * Get the package with which this report will be shared.
+ */
+ public @NonNull String getRequestingPackage() {
+ return mRequestingPackage;
+ }
+
+ /**
+ * Get the flags requested for this pending report.
+ *
+ * @see #FLAG_CONFIRMATION_DIALOG
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Get the time this pending report was posted.
+ */
+ public long getTimestamp() {
+ return mTimestamp;
+ }
+
+ /**
+ * Get the URI associated with this PendingReport. It can be used to
+ * re-retrieve it from {@link IncidentManager} or set as the data field of
+ * an Intent.
+ */
+ public @NonNull Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * String representation of this PendingReport.
+ */
+ @Override
+ public @NonNull String toString() {
+ return "PendingReport(" + getUri().toString() + ")";
+ }
+ }
+
+ /**
+ * Listener for the status of an incident report being authroized or denied.
+ *
+ * @see #requestAuthorization
+ * @see #cancelAuthorization
+ */
+ public static class AuthListener {
+ IIncidentAuthListener.Stub mBinder = new IIncidentAuthListener.Stub() {
+ @Override
+ public void onReportApproved() {
+ AuthListener.this.onReportApproved();
+ }
+
+ @Override
+ public void onReportDenied() {
+ AuthListener.this.onReportDenied();
+ }
+ };
+
+ /**
+ * Called when a report is approved.
+ */
+ public void onReportApproved() {
+ }
+
+ /**
+ * Called when a report is denied.
+ */
+ public void onReportDenied() {
+ }
+ }
/**
* @hide
@@ -56,12 +252,76 @@ public class IncidentManager {
reportIncidentInternal(args);
}
- private class IncidentdDeathRecipient implements IBinder.DeathRecipient {
- @Override
- public void binderDied() {
- synchronized (this) {
- mService = null;
- }
+ /**
+ * Request authorization of an incident report.
+ */
+ @RequiresPermission(android.Manifest.permission.REQUEST_INCIDENT_REPORT_APPROVAL)
+ public void requestAuthorization(int callingUid, String callingPackage, int flags,
+ AuthListener listener) {
+ try {
+ getCompanionServiceLocked().authorizeReport(callingUid, callingPackage, flags,
+ listener.mBinder);
+ } catch (RemoteException ex) {
+ // System process going down
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Cancel a previous request for incident report authorization.
+ */
+ @RequiresPermission(android.Manifest.permission.REQUEST_INCIDENT_REPORT_APPROVAL)
+ public void cancelAuthorization(AuthListener listener) {
+ try {
+ getCompanionServiceLocked().cancelAuthorization(listener.mBinder);
+ } catch (RemoteException ex) {
+ // System process going down
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Get incident (and bug) reports that are pending approval to share.
+ */
+ @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS)
+ public List<PendingReport> getPendingReports() {
+ List<String> strings;
+ try {
+ strings = getCompanionServiceLocked().getPendingReports();
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ final int size = strings.size();
+ ArrayList<PendingReport> result = new ArrayList(size);
+ for (int i = 0; i < size; i++) {
+ result.add(new PendingReport(Uri.parse(strings.get(i))));
+ }
+ return result;
+ }
+
+ /**
+ * Allow this report to be shared with the given app.
+ */
+ @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS)
+ public void approveReport(Uri uri) {
+ try {
+ getCompanionServiceLocked().approveReport(uri.toString());
+ } catch (RemoteException ex) {
+ // System process going down
+ throw new RuntimeException(ex);
+ }
+ }
+
+ /**
+ * Do not allow this report to be shared with the given app.
+ */
+ @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS)
+ public void denyReport(Uri uri) {
+ try {
+ getCompanionServiceLocked().denyReport(uri.toString());
+ } catch (RemoteException ex) {
+ // System process going down
+ throw new RuntimeException(ex);
}
}
@@ -79,22 +339,47 @@ public class IncidentManager {
}
private IIncidentManager getIIncidentManagerLocked() throws RemoteException {
- if (mService != null) {
- return mService;
+ if (mIncidentService != null) {
+ return mIncidentService;
}
- synchronized (this) {
- if (mService != null) {
- return mService;
+ synchronized (mLock) {
+ if (mIncidentService != null) {
+ return mIncidentService;
}
- mService = IIncidentManager.Stub.asInterface(
+ mIncidentService = IIncidentManager.Stub.asInterface(
ServiceManager.getService(Context.INCIDENT_SERVICE));
- if (mService != null) {
- mService.asBinder().linkToDeath(new IncidentdDeathRecipient(), 0);
+ if (mIncidentService != null) {
+ mIncidentService.asBinder().linkToDeath(() -> {
+ synchronized (mLock) {
+ mIncidentService = null;
+ }
+ }, 0);
}
- return mService;
+ return mIncidentService;
}
}
+ private IIncidentCompanion getCompanionServiceLocked() throws RemoteException {
+ if (mCompanionService != null) {
+ return mCompanionService;
+ }
+
+ synchronized (this) {
+ if (mCompanionService != null) {
+ return mCompanionService;
+ }
+ mCompanionService = IIncidentCompanion.Stub.asInterface(
+ ServiceManager.getService(Context.INCIDENT_COMPANION_SERVICE));
+ if (mCompanionService != null) {
+ mCompanionService.asBinder().linkToDeath(() -> {
+ synchronized (mLock) {
+ mCompanionService = null;
+ }
+ }, 0);
+ }
+ return mCompanionService;
+ }
+ }
}