diff options
| author | Joe Onorato <joeo@google.com> | 2019-01-29 19:34:40 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-01-29 19:34:40 +0000 |
| commit | 917955a4e669c9b237db621359ed67117758605a (patch) | |
| tree | 2a7bb4adc7767442dc2ba136a654019c3b03111f /core/java/android | |
| parent | afe6ec4b271890b3ea943c1208acd6282642ee9b (diff) | |
| parent | e21ab7eab46d1c99e0e3e3506edaca096f796e2d (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.java | 9 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 8 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 12 | ||||
| -rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 2 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 13 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManagerInternal.java | 2 | ||||
| -rw-r--r-- | core/java/android/content/pm/PermissionInfo.java | 14 | ||||
| -rw-r--r-- | core/java/android/os/IncidentManager.java | 317 |
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; + } + } } |
