Background
Historically, Android Custom permissions have been a mess and were install order dependent, which was known to expose vulnerabilities.
Prior to API 21, there was an unsettling workaround whereby declaring the custom permission of another application in your Manifest, granted the permission... However, since API 21, only one application can declare a custom permission and the installation of a further application declaring this same permission, will be prevented.
The alternatives are to reinstall the application requiring the permission, so they are detected by the System, but that is not a good user experience. Or check at runtime for the permissions of the calling application, but that is not without its theoretical flaws.
Problem
As of Android Marshmallow (6.0 - API 23) an application needs to request permission from the user, to use its own custom permission. A declared custom permission is not automatically granted.
This seems peculiar, given that only one application can now declare it.
To replicate
Declare the custom permission and a BroadcastReceiver in the Manifest.
<permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
android:description="@string/control_description"
android:icon="@mipmap/ic_launcher"
android:label="@string/control_label"
android:protectionLevel="normal or dangerous"/>
<uses-permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
// etc
<receiver
android:name="com.example.app.MyBroadcastReceiver"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
<intent-filter android:priority="999">
<action android:name="com.example.app.REQUEST_RECEIVER"/>
</intent-filter>
</receiver>
From a third-party application, declare that it uses the custom permission in the Manifest (and accept it via a dialog or the settings) and call:
final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
@Override
public void onReceive(final Context context, final Intent intent) {
// getResultCode();
}
}, null, Activity.RESULT_CANCELED, null, null);
The result will return CANCELED and the log will show:
system_process W/BroadcastQueue: Permission Denial: receiving Intent { act=com.example.app.REQUEST_RECEIVER flg=0x10 (has extras) } to com.example.app/.MyBroadcastReceiver requires com.example.app.permission.CONTROL_EXAMPLE_APP due to sender com.example.thirdparty
If I use the standard ActivityCompat.requestPermissions()
dialog to allow the user to accept the permission, the receiver, as you would expect, works correctly.
Question
Is this expected behaviour? Or have I somehow overlooked something?
It would seem ridiculous to raise a dialog saying
The application Example App wants permission to use Example App
And it may indeed concern the user, providing them with such a nonsensical request.
I can of course change the permission description and name, to something that they would accept, such as 'communicate with other installed applications', but before I sigh and take that approach, I thought I'd ask this question.
Note
The example of the ordered broadcast is to replicate the problem. My application does use other implementations of content providers and a bound service. It is not an alternative implementation I require, it's confirmation of the issue.
Thank you for reading this far.
Edit: To clarify, for other implementations, such as declaring a permmission on a Service (which would be most simple to replicate) the declared custom permission is automatically granted.