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.
You can use the sharedUserId attribute in the AndroidManifest. xml 's manifest tag of each package to have them assigned the same user ID. By doing this, for purposes of security the two packages are then treated as being the same app, with the same user ID and file permissions.
requestPermissions(thisActivity, new String[]{Manifest. permission. READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); Android system creates a popup dialog to request permission.
You need to declare the permissions in the manifest file first before you request for them programmatically. refer this for more information. declaring the permission in the manifest file is static type declaration by which your os know what kind of permission your app might require.
As I understood you tried to do next thing (At least, that's how I was able to reproduce your problem):
You declare your new custom permission in first (lets call it F) application
<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"/>
You define that your F app uses com.example.app.permission.CONTROL_EXAMPLE_APP
permission. That is right as the guideline says.
<uses-permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
You declare your custom broadcast receiver in your F app. To communicate with that broadcast your app (it's no matter which one, F or other app) must obtain your custom permission
<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>
You define that you second (lets call it S) application uses com.example.app.permission.CONTROL_EXAMPLE_APP
permission. Because you want to allow S app to send broadcast messages to F app receiver.
<uses-permission
android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
Finally you try to send broadcast message from your S app using this code.
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);
And, this is important, you granted permission to your S app, but you didn't grant permission to your F app.
As result your broadcast receiver declared in F app didn't receive anything.
After you granted permission to your F app (Note that now S and F granted your custom permission) everything works fine. Broadcast receiver declared in F app received message from S app.
I guess that is correct behaviour, because this doc says us:
Note that, in this example, the DEBIT_ACCT permission is not only declared with the element, its use is also requested with the element. You must request its use in order for other components of the application to launch the protected activity, even though the protection is imposed by the application itself.
And app which declare permission also must request the same permission to communicate with itself.
As result, android API 23 should to get access to use your permission form user first. And we must to get 2 granted permissions, first from F app (because guidline says as that) and second from S app (because we just need to get access).
But I didn't catch your next point:
It would seem ridiculous to raise a dialog saying
The application Example App wants permission to use Example App
My native Android API 23 displays me something like that:
The application Example App wants
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With