androidgoogle-cloud-messagingandroid-8.0-oreolegacy-app

Android GCM - WakefulBroadcastReceiver.startWakefulService crash due to IllegalStateException 8.0


We just migrated app's target api to Android API 27 (8.1) and it keeps on crashing when notification arrives specially when the app is in the background.

java.lang.RuntimeException: Unable to start receiver <package>.service.GCMBroadcastReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
    at android.app.ActivityThread.handleReceiver(ActivityThread.java:3194)
    at android.app.ActivityThread.-wrap17(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6494)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
 Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
    at android.app.ContextImpl.startService(ContextImpl.java:1477)
    at android.content.ContextWrapper.startService(ContextWrapper.java:650)
    at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
    at <package>.service.GCMBroadcastReceiver.onReceive(GCMBroadcastReceiver.java:32)
    at android.app.ActivityThread.handleReceiver(ActivityThread.java:3187)
    at android.app.ActivityThread.-wrap17(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6494) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 

Solution

  • This is how I fix the issue:

    Why this issue happens?

    Due to the new Background Execution Limits of Android 8 and you should not start services background.

    How I fixed it

    Migrate your GCMIntetService to JobIntentService instead of IntentService.

    Please follow this steps: 1) Add the BIND_JOB_SERVICE permission to your service:

    <service android:name=".service.GCMIntentService"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE"/>
    

    2) In your GCMIntentService, instead extending the IntentService, use android.support.v4.app.JobIntentService and override onHandleWork then remove the override in you onHandleIntent.

    public class GCMIntentService extends JobIntentService {
    
        // Service unique ID
        static final int SERVICE_JOB_ID = 50;
    
        // Enqueuing work in to this service.
        public static void enqueueWork(Context context, Intent work) {
            enqueueWork(context, GCMIntentService.class, SERVICE_JOB_ID, work);
        }
    
        @Override
        protected void onHandleWork(@NonNull Intent intent) {
            onHandleIntent(intent);
        }
    
        private void onHandleIntent(Intent intent) {
            //Handling of notification goes here
        }
    }
    

    Then finally, in your GCMBroadcastReceiver, enqueue your GCMIntentService.

    public class GCMBroadcastReceiver extends WakefulBroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // Explicitly specify that GcmIntentService will handle the intent.
            ComponentName comp = new ComponentName(context.getPackageName(),
                    GCMIntentService.class.getName());
            // Start the service, keeping the device awake while it is launching.
            // startWakefulService(context, (intent.setComponent(comp)));
    
            //setResultCode(Activity.RESULT_OK);
    
            GCMIntentService.enqueueWork(context, (intent.setComponent(comp)));
        }
    }
    

    This implementation work for me after we update our target sdk to 27 and I hope it works for you.