3

In my application I have registered a broadcast receiver for an implicit broadcast by another application protected with permission :

<receiver
    android:name=".receiver.MyReceiver"
    android:exported="true"
    android:permission="owner.custom.permission">
    <intent-filter>
        <action android:name="owner.custom.broadcast"/>
    </intent-filter>
</receiver>

In MyReceiver#onReceive() I am invoking a JobIntentService MyService using enqueueWork():

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.i(TAG, "Received the broadcast");
        MyService.enqueueWork(context, getServiceIntent(context));
    }

    private Intent getServiceIntent(final Context context) {
        final Intent intent = new Intent(context, MyService.class);
        intent.putExtra("someKey", true);
        return intent;
    }
}

I have the following method in MyService :

public static void enqueueWork(final Context context, final Intent work) {
        enqueueWork(context, MyService.class, 111, work);
    }

Now whenever owner.custom.broadcast is broadcast, MyReceiver is not triggered and I can see the following logs :

07-23 03:56:29.755  3335  3361 W BroadcastQueue: Background execution not allowed: receiving Intent { act=owner.custom.broadcast flg=0x10 } to com.amazon.myApp/.receiver.MyReceiver

Now the thing is I am listening to another such 3rd party implicit broadcast with a different broadcast receiver and invoking MyService over there and it works fine. I am also listening for BOOT_COMPLETED broadcast in a yet another broadcast receiver and invoking MyService over there and it works fine there too.
What are the possible causes for this error which would help me identify if I'm missing something.

UPDATE :
I am now just trying to get the broadcast receiver to trigger but I am still getting the same error. I am trying with nothing but a log line in the receiver :

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.i(TAG, "Received the broadcast");
    }
}
iammrmehul
  • 730
  • 1
  • 14
  • 35
  • Possible duplicate of [Background execution not allowed receiving intent BOOT\_COMPLETED](https://stackoverflow.com/questions/50040617/background-execution-not-allowed-receiving-intent-boot-completed) – Hardik Bambhania Jul 23 '19 at 09:17

4 Answers4

3

Android O limits the implicit broadcast, you can't execute a background service in the receiver.

However, it only limits the static receivers, you can register your receiver in the code to trigger your service.

Of course, in some case, you don't want to do it "programmatically", then you should check the error case, from this link http://androidxref.com/8.1.0_r33/xref/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java#1275 (Line:1275), I find the error (not sure if this is the same as your system version).

We can see there are few conditions to access to this code block, we analyze them one by one, all we want to do is make the condition equals false:

(r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0

It means if we don't want the background to receive the intent the condition will be true, and usually, we don't add this flag because we want the background to receive the broadcast, go ahead.

r.intent.getComponent() == null

It should not be null in any of our case, go ahead.

r.intent.getPackage() == null

Same above, go ahead.

r.intent.getFlags()&Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0

It means we cannot have a flag called Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, I think we can try this, but you will see this in the Intent class:

   /**
     * If set, the broadcast will always go to manifest receivers in background (cached
     * or not running) apps, regardless of whether that would be done by default.  By
     * default they will only receive broadcasts if the broadcast has specified an
     * explicit component or package name.
     *
     * NOTE: dumpstate uses this flag numerically, so when its value is changed
     * the broadcast code there must also be changed to match.
     *
     * @hide
     */
    public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;

It's hidden, but you can just hardcode the integer in your project, now add this flag to your intent to try if your code is work.

   intent.addFlags(0x01000000)

Good luck :)

Note: this solution will NOT resolve to receive the system implicit broadcast to run background tasks.

Library545
  • 371
  • 1
  • 5
  • Wouldn't a custom broadcast be an explicit broadcast? Not an implicit one? – Matt Sep 17 '19 at 16:19
  • what if I comment the entire else if block which those conditions written? – Shadow Jan 10 '20 at 06:10
  • do you want to build your own Android ROM? @Shadow – Library545 Jan 11 '20 at 10:46
  • Yes @Library545 – Shadow Jan 13 '20 at 05:19
  • Yes, you can, but I suggest no because of the security. If you want your own service to pass this checker to do some "special things," you can add an external condition append to these conditions. For example, add key&secret into the intent bundle and check the key&secret of handled intent @Shadow and of course, the easiest way to do that is let your service apk signed with the system signature – Library545 Jan 13 '20 at 11:28
1

This is an old question, but I found a solution which worked for me.

As mentioned here

Context-registered receivers receive broadcasts as long as their registering context is valid. For an example, if you register within an Activity context, you receive broadcasts as long as the activity is not destroyed. If you register with the Application context, you receive broadcasts as long as the app is running.

I had to remove the receiver declaration in the Manifest completely and register my receiver during runtime, using the Application context!

IntentFilter filter = new IntentFilter("owner.custom.broadcast");
getContext().getApplicationContext().registerReceiver(new MyReceiver(), filter);

and then

public class MyReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        context.unregisterReceiver(this);
        // ....
    }
}
0

Try this

I faced a similar problem year ago, I'm not pretty sure of this, but since its not allowed for background execution then execute it in foreground using Foreground Service, you can achieve that by starting a service that is connected to a notification, then in your service you can trigger your broadcast and that should work.

I hope my answer helps you.

Farouq Afghani
  • 296
  • 1
  • 6
  • But why is it working when I am listening for a different 3rd party broadcast with permission and triggering the same service in the same way. – iammrmehul Jul 23 '19 at 09:42
0

I'm not sure why this solution worked (maybe someone else can elaborate on why) but I was able to get my broadcast receiver to trigger by declaring the permission in my Manifest itself and and also using the same. Find the code changes below :

<permission
    android:name="owner.custom.permission"
    android:protectionLevel="signatureOrSystem">
</permission>
.
.
.
<uses-permission android:name="owner.custom.permission" />
iammrmehul
  • 730
  • 1
  • 14
  • 35
  • Based on what official android page said 'Broadcasts that require a signature permission are exempted from this restriction, since these broadcasts are only sent to apps that are signed with the same certificate, not to all the apps on the device.' What you wrote should help, but actually in my case for some reason it don't helps. – Maksim Novikov Dec 26 '21 at 13:51