Android 8.0: java.lang.IllegalStateException: Not allowed to start service Intent

Solution 1:

I got solution. For pre-8.0 devices, you have to just use startService(), but for post-7.0 devices, you have to use startForgroundService(). Here is sample for code to start service.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(context, ServedService.class));
    } else {
        context.startService(new Intent(context, ServedService.class));
    }

And in service class, please add the code below for notification:

@Override
public void onCreate() {
    super.onCreate();
    startForeground(1,new Notification());
}

Where O is Android version 26.

If you don't want your service to run in Foreground and want it to run in background instead, post Android O you must bind the service to a connection like below:

Intent serviceIntent = new Intent(context, ServedService.class);
context.startService(serviceIntent);
context.bindService(serviceIntent, new ServiceConnection() {
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         //retrieve an instance of the service here from the IBinder returned 
         //from the onBind method to communicate with 
     }

     @Override
     public void onServiceDisconnected(ComponentName name) {
     }
}, Context.BIND_AUTO_CREATE);

Solution 2:

The permitted situations are a temporary whitelist where the background service behaves the same as before Android O.

Under certain circumstances, a background app is placed on a temporary whitelist for several minutes. While an app is on the whitelist, it can launch services without limitation, and its background services are permitted to run. An app is placed on the whitelist when it handles a task that's visible to the user, such as:

  • Handling a high-priority Firebase Cloud Messaging (FCM) message.
  • Receiving a broadcast, such as an SMS/MMS message.
  • Executing a PendingIntent from a notification.
  • Starting a VpnService before the VPN app promotes itself to the foreground.

Source: https://developer.android.com/about/versions/oreo/background.html

So in other words if your background service does not meet the whitelist requirements you have to use the new JobScheduler. It's basically the same as a background service, but it gets called periodically instead of running in the background continuously.

If you're using an IntentService, you can change to a JobIntentService. See @kosev's answer below.

Solution 3:

The best way is to use JobIntentService which uses the new JobScheduler for Oreo or the old services if not available.

Declare in your manifest:

<service android:name=".YourService"
         android:permission="android.permission.BIND_JOB_SERVICE"/>

And in your service you have to replace onHandleIntent with onHandleWork:

public class YourService extends JobIntentService {

    public static final int JOB_ID = 1;

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, YourService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // your code
    }

}

Then you start your service with:

YourService.enqueueWork(context, new Intent());

Solution 4:

If the service is running in a background thread by extending IntentService, you can replace IntentService with JobIntentService which is provided as part of Android Support Library

The advantage of using JobIntentService is, it behaves as an IntentService on pre-O devices and on O and higher, it dispatches it as a job

JobScheduler can also be used for periodic/on demand jobs. But, ensure to handle backward compatibility as JobScheduler API is available only from API 21