Background
Historically, Android Custom permissions have been a mess and were install order dependent, which was known to expose vulnerabilities.
Prior
While it might be ambiguous for the user to see a permission request for the app which is declared in the same app, it is how android is designed to run since marshmallow. I think, on android's perspective, the behavior is as intended and correct.
I don't think it's completely true that a declared custom permission will not be automatically granted to the application. For when the custom permission has the protection level "normal" or "signature", then the permission is granted at install time. Otherwise, if the protection level is "dangerous", then it is a runtime permission and it works just like other dangerous permissions: you will need to prompt the user to grant the permission to the application.
I think the problem in your example is that you explicitly require that both your applications are granted the custom permission.
This part requires, that the com.example.thirdparty app has the permission:
<receiver
android:name="com.example.app.MyBroadcastReceiver"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
And this part requires, that the com.example.app application has the permission as well:
context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", ...
You mention that you don't have this problem when using a service. I don't know how exactly you use the service, but if you simply declare it like this:
<service
android:name="com.example.app.MyService"
android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
and then bind it like this:
context.bindService(serviceIntent, mServiceConnection, ...
then it's enough if com.example.thirdparty has the permission granted, while com.example.app doesn't need to have it.
In other words, I think this behavior is by design, and the difference you see between the Broadcast and Service behavior is because in the Broadcast case you specifically request that the com.example.app has the custom permission, whereas in the Service case you don't.
I hope I didn't misunderstand your problem. If I did, please let me know and I'll delete this response.
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
First add permissions in manifest file after
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />