According to the migration guide to Android O given by Google, most of the implicit broadcast intent should not be registered in the Manifest (minus a few exceptions found here) but explicit broadcast intents remain untouched.
We are looking to move any needed broadcast away from the manifest. But how do we recognise if a receiver is implicit? Is there a general rule?
Here is a sample of the broadcasts we register in the manifest. Should we look only at the "action" tag and see if it is whitelisted to keep it in the manifest?
<receiver
android:name=".receiver.ImageBroadcastReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.hardware.action.NEW_PICTURE" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="image/*" />
</intent-filter>
</receiver>
<receiver
android:name=".receiver.InstallReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.JoinEventReceiver" >
<intent-filter>
<action android:name="JOIN_ACTION" />
<action android:name="CANCEL_ACTION" />
<action android:name="DECLINE_ACTION" />
</intent-filter>
</receiver>
For example, the "com.android.vending.INSTALL_REFERRER" intent is not whitelisted. Should we register it in an Activity? If so wouldn't it be never fired as when we register it the app is already installed? This is what confuses me when trying to understand if a broadcast receiver is implicit or explicit as I thought I only had to check that "action" tag.
But how do we recognise if a receiver is implicit?
If the Intent has a ComponentName, the Intent is explicit. Otherwise, it is implicit.
That ComponentName can be obtained in one of a few ways, including:
It can be directly put on the Intent (e.g., new Intent(this, TheReallyAwesomeReceiver.class)
It can be directly put on the Intent after using PackageManager and queryIntentReceivers() to find the right one based on action strings, etc.
It can be derived by the system from the action string, etc. plus the package defined via setPackage()
Should we look only at the "action" tag and see if it is whitelisted to keep it in the manifest?
No. You also need to think about the nature of the broadcast: is it going to any registered receiver, or only to a specific app?
For example, the "com.android.vending.INSTALL_REFERRER" intent is not whitelisted. Should we register it in an Activity?
No. That broadcast will only go to the app that was recently installed, and so it must be an explicit Intent. The action string and such are there to help the system determine which of your registered receivers is the relevant one.
Contrast that with ACTION_PACKAGE_ADDED. That is broadcast to any registered receiver; it is not going to just one specific app. Hence, that Intent must be implicit (as otherwise it would have a ComponentName identifying a specific receiver in a specific app). And, since ACTION_PACKAGE_ADDED is not on the whitelist, the assumption should be that you cannot register for this broadcast in the manifest on Android 8.0+.
Related
I want to declare a broadcast receiver which can listen to system broadcasts like PACKAGE_ADDED, PACKAGE_REPLACED, for e.g.
<receiver
android:name="com.sample.cli.xyz.XyzReceiver"
android:exported="true"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REPLACED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
</intent-filter>
</receiver>
If I keep exported="true" here, any app can send the broadcast and it can be a security issue. As per Android documentation if we have even 1 intent-filter in receiver tag then, default value of exported is considered "true".
My question is if I explicitly declare this attribute as "false" (android:exported="false"), along with intent-filters, will it make it more secure and make it accessible only by system and not other apps?
Tried the combination (exported="false" along with intent-filter declared in receiver) asked in question, in a sample app and found that receiver can still listen to system events like PACKAGE_ADDED, PACKAGE_REMOVED etc.
As per the Android O developer preview, we can no longer use the PACKAGE_REPLACED intent to use with a receiver declared inside the manifest.
The alternative is MY_PACKAGE_REPLACED. But this intent does not seem to fire when i update the app via android studio after code changes. Whereas the old broader intent always fired properly.
<receiver
android:name=".Receivers.BootEventReceiver"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
assume that the receiver itself just prints a log message in onReceive().
Googling suggested this seems to be some android manifest merger issue. But i really couldn't follow how to solve this.
Can someone point me in the right direction
Instead of having one receiver with two intent filters, i decided to make a separate receiver with MY_PACKAGE_REPLACED intent filter.
The receiver started working again. Hope this helps anyone interested
My app registers in the manifest a broadcastreceiver for PHONE_STATE intent.
<receiver android:name=".receiver.PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Everything worked fine until i installed another app which handles phone calls (in specific it records audio of phone calls). From that moment my registered receiver does not fire every time. If i remote the second app all returns to be ok.
I assume that this app (as mine) registers a broadcastreceiver for PHONE_STATE intent. Is it possible that this app "consumes" the broadcastreceiver and so it will not fire mine?
i assume that the other broadcast consumer has called the abortBroadcast() method, that ... will prevent any other broadcast receivers from receiving the broadcast.
While it is possible to declare a 'Local' BroadcastReceiver via code so it receives intents published via a LocalBroadcastManager.Ex
LocalBroadcastManager.getInstance(this).registerReceiver(new FooReceiver(), new IntentFilter("foo_intent_filter"));
I wonder if it is possible to declare such receiver via the manifest.xml (cleaner) .
When I use the 'manifest way', the receiver is not 'receiving' the intents.
<receiver
android:name="FooReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="foo_intent_filter" />
</intent-filter>
</receiver>
Am I missing something? or the code-way is the only viable solution.
Thanks
I wonder if it is possible to declare such receiver via the manifest.xml (cleaner) .
First, that is not possible.
Second, registering in the manifest has little to do with it being "cleaner". It is to allow Android to instantiate the receiver on its own, so that you can respond to broadcasts when your process is not running. And, in the specific example that you cite, it is to allow any app on the system to send you a broadcast. Neither of those are relevant for LocalBroadcastManager.
I was wondering if it is possible to find a list that includes all the receivers associated to a certain action.
For example I have the following receiver that executes everytime that an SMS is received:
<receiver android:name=".SmsReceiver" android:enabled="true">
<intent-filter android:priority="101">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
So with the priority="101" it´s executed even before than the default message service in Android.
I would like to find all the intent-filter associated to a certail action, in this case "android.provider.Telephony.SMS_RECEIVED"
I tried to get into /data/data/com.android.provider.telephony/databases but no info is stored in ther.
It would be great if anybody could tell me where can I find that info, and even if it is possible.
Regards,
Pablo
Use PackageManager and queryBroadcastReceivers() to find out all of the BroadcastReceivers that will respond to a given Intent. In your case, you would create an SMS_RECEIVED Intent.