Background execution not allowed receiving intent BOOT_COMPLETED
W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.BOOT_COMPLETED **flg=0x400010** }
You test the intent from adb shell, may be am broadcast -a android.intent.action.BOOT_COMPLETED
The flg=0x400010
is different with flg=0x9000010
which the Android system sent during boot.
You could find the flag definition at frameworks/base/core/java/android/content/Intent.java
.
The flg=0x400010
does not has the bit FLAG_RECEIVER_FOREGROUND = 0x10000000
.
So, if you want to test the intent from adb shell, you could use
am broadcast -a android.intent.action.BOOT_COMPLETED *--receiver-include-background.*
Self-registering your receiver(s) in a code for the needed implicit intents is really the right way to start receiving that intents. No service is needed for this (in most cases, see below...). But you need to be aware of the following in order not to be confused during testing and not to break earlier implementation:
- Self-registering should be done once per the application run. In terms of Java / Kotlin application data: once per a static field life. So one static boolean field should allow you to know: if you need to self-register (e.g. after reboot or after Android system killed your app later...) or not (I cite working code from this commit: https://github.com/andstatus/todoagenda/commit/74ffc1495f2c4bebe5c43aab13389ea0ea821fde ):
private static volatile boolean receiversRegistered = false;
private static void registerReceivers(Context contextIn) {
if (receiversRegistered) return;
Context context = contextIn.getApplicationContext();
EnvironmentChangedReceiver receiver = new EnvironmentChangedReceiver();
IntentFilter providerChanged = new IntentFilter();
providerChanged.addAction("android.intent.action.PROVIDER_CHANGED");
providerChanged.addDataScheme("content");
providerChanged.addDataAuthority("com.android.calendar", null);
context.registerReceiver(receiver, providerChanged);
IntentFilter userPresent = new IntentFilter();
userPresent.addAction("android.intent.action.USER_PRESENT");
context.registerReceiver(receiver, userPresent);
Log.i(EventAppWidgetProvider.class.getName(), "Registered receivers from " + contextIn.getClass().getName());
receiversRegistered = true;
}
- Insert the call of your registerReceivers method to all possible entry points of your application in order to maximize chances that the receivers are registered even if your application was started by Android system only once, e.g.:
@Override
public void onUpdate(Context baseContext, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
registerReceivers(baseContext);
...
}
You may leave your receivers being registered to the same intents in AndroidManifest.xml file (as this works for Android before v.7 ...), but note that in this case in logcat you will still see "Background execution not allowed" with a reference to your receivers. This only means that registration via the AndroidManifest.xml doesn't work (as expected for Android 8+) but self-registered receivers should be called anyway!
As I noted above, starting foreground service is generally not needed for a light widget. Moreover, a User won't like constantly seeing notification that your "widget" is running in the foreground (and thus constantly eating resources). The only case, when this may be really needed, is when Android kills your application too often and thus deletes that self-registration done after reboot. I think that making your "widget application" as light as possible (requiring as few memory and CPU resources, as possible...) is the right way to ensure that your widget app will be killed only in critical cases for your device... Maybe you should split your large app in two, making a widget sort of a launcher for the heavyweight app that needs to work from time to time...