Added a new "incidentReportApprover" permission protection flag.
This gives the ONE app installed on the system the permission to
authorize the sharing of incident and bug reports with an app.
Currently that app is PermissionController. Package Manager
enforces that there is only one installed, and refused to boot
if that isn't the case.
Bug: 123543706
Test: bit GooglePermissionControllerTest:*
Change-Id: I76a7fad0ea36359bbb0ff09669df46202d059dab
diff --git a/api/system-current.txt b/api/system-current.txt
index da3b7f4..7214eb7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -18,6 +18,7 @@
field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
+ field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String BACKUP = "android.permission.BACKUP";
field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
@@ -1489,6 +1490,7 @@
method @NonNull public android.content.pm.dex.ArtManager getArtManager();
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
+ method public String getIncidentReportApproverPackageName();
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract android.graphics.drawable.Drawable getInstantAppIcon(String);
method public abstract android.content.ComponentName getInstantAppInstallerComponent();
@@ -1610,6 +1612,7 @@
field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+ field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
diff --git a/api/test-current.txt b/api/test-current.txt
index 9c27535..2d65484 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4,6 +4,7 @@
public static final class Manifest.permission {
field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
+ field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
@@ -413,6 +414,7 @@
public abstract class PackageManager {
method public abstract boolean arePermissionsIndividuallyControlled();
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
+ method public String getIncidentReportApproverPackageName();
method public abstract int getInstallReason(String, @NonNull android.os.UserHandle);
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
@@ -434,6 +436,7 @@
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+ field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 4491b95..a937422 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3026,6 +3026,15 @@
}
@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/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 7bd8c4e..a6a6f01 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -688,6 +688,8 @@
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 0aa33c8..3a675c9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -6744,6 +6744,19 @@
}
/**
+ * @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 c9a4c82..738730e 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -56,6 +56,7 @@
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 @@
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 5d2cf0a..e776984 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -213,6 +213,16 @@
@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 @@
PROTECTION_FLAG_WELLBEING,
PROTECTION_FLAG_DOCUMENTER,
PROTECTION_FLAG_CONFIGURATOR,
+ PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -431,6 +442,9 @@
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7184c7a..14143d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -115,6 +115,7 @@
<protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" />
<protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" />
<protected-broadcast android:name="android.app.action.SHOW_DEVICE_MONITORING_DIALOG" />
+ <protected-broadcast android:name="android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
@@ -2798,6 +2799,15 @@
<permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
android:protectionLevel="signature|privileged|development" />
+ <!-- @hide @SystemApi @TestApi
+ Allow an application to approve incident and bug reports to be
+ shared off-device. There can be only one application installed on the
+ device with this permission, and since this is a privileged permission, it
+ must be in priv-app.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.APPROVE_INCIDENT_REPORTS"
+ android:protectionLevel="signature|incidentReportApprover" />
+
<!-- ==================================== -->
<!-- Private permissions -->
<!-- ==================================== -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index de6468d..0abe456 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -277,6 +277,9 @@
<!-- Additional flag from base permission type: this permission automatically
granted to device configurator -->
<flag name="configurator" value="0x80000" />
+ <!-- Additional flag from base permission type: this permission designates the app
+ that will approve the sharing of incident reports. -->
+ <flag name="incidentReportApprover" value="0x100000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1db8135..67b0652 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3493,6 +3493,13 @@
-->
<string name="config_defaultAttentionService" translatable="false"></string>
+ <!-- The package name for the incident report approver app.
+ This app is usually PermissionController or an app that replaces it. When
+ a bugreport or incident report with EXPLICT-level sharing flags is going to be
+ shared, this app will be sent the PENDING_INCIDENT_REPORTS_CHANGED broadcast.
+ -->
+ <string name="config_incidentReportApproverPackage" translatable="false">com.android.permissioncontroller</string>
+
<!-- The package name for the system's content capture service.
This service must be trusted, as it can be activated without explicit consent of the user.
If no service with the specified name exists on the device, content capture will be
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index aefa9df..ed076da 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3580,4 +3580,6 @@
<!-- For Attention Service -->
<java-symbol type="integer" name="config_attentionMaximumExtension" />
<java-symbol type="integer" name="config_attentionApiTimeout" />
+
+ <java-symbol type="string" name="config_incidentReportApproverPackage" />
</resources>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 1684138..3331f3a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -141,6 +141,7 @@
<permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
<permission name="android.permission.GET_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.APPROVE_INCIDENT_REPORTS"/>
</privapp-permissions>
<privapp-permissions package="com.android.phone">
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 265d07a..d2547d9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1350,6 +1350,7 @@
final @Nullable String mDocumenterPackage;
final @Nullable String mConfiguratorPackage;
final @Nullable String mAppPredictionServicePackage;
+ final @Nullable String mIncidentReportApproverPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2879,6 +2880,7 @@
mConfiguratorPackage =
mContext.getString(R.string.config_deviceConfiguratorPackageName);
mAppPredictionServicePackage = getAppPredictionServicePackageName();
+ mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -20112,6 +20114,10 @@
return contentCaptureServiceName.substring(0, separatorIndex);
}
+ public String getIncidentReportApproverPackageName() {
+ return mContext.getString(R.string.config_incidentReportApproverPackage);
+ }
+
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
@@ -23275,6 +23281,8 @@
return mDocumenterPackage;
case PackageManagerInternal.PACKAGE_CONFIGURATOR:
return mConfiguratorPackage;
+ case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
+ return mIncidentReportApproverPackage;
}
return null;
}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 17f8347..848cee0 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -251,6 +251,9 @@
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_CONFIGURATOR)
!= 0;
}
+ public boolean isIncidentReportApprover() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INCIDENT_REPORT_APPROVER) != 0;
+ }
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3c89d78..22780e6 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1716,6 +1716,14 @@
// this app is the documenter, then it gets the permission.
allowed = true;
}
+ if (!allowed && bp.isIncidentReportApprover()
+ && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER,
+ UserHandle.USER_SYSTEM))) {
+ // If this permission is to be granted to the incident report approver and
+ // this app is the incident report approver, then it gets the permission.
+ allowed = true;
+ }
}
return allowed;
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 5b02266..a01d589 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1151,6 +1151,10 @@
return null;
}
+ public String getIncidentReportApproverPackageName() throws RemoteException {
+ return null;
+ }
+
@Override
public boolean isPackageStateProtected(String packageName, int userId) throws RemoteException {
return false;