My app is for now still targeting SDK 25
I'm trying to replace my background services in order to be able to target SDK 26.
In order to do so I now start my IntentService with
ContextCompat.startForegroundService()
If I understand the documentation correctly I then have 5 seconds to call startForeground() on the service.
When doing so it works fine.
But sometimes my service doesn't have any work to do, so it just exits right away (onHandleIntent() doesn't do anything) and yet the app crashes with the following error
AndroidRuntime: FATAL EXCEPTION:
Process: com.myAPPPackage, PID: 3855
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)
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)
What about the 5 seconds delay in that case?
I can see that the service onDestroy() method is called like a few ms after the call to ContextCompat.startForegroundService()
Any idea why the app is crashing like that?
Any idea why the app is crashing like that?
You are not calling startForeground().
But sometimes my service doesn't have any work to do, so it just exits right away
You need to call startForeground() first.
Or have whatever it is that is calling startForegroundService() determine whether there is any work to do first, before calling startForegroundService(). That way, you do not have to bother calling startForegroundService() if there is no need for a foreground service.
If I understand the documentation correctly I then have 5 seconds to call startForeground() on the service.
Yes, but that does not mean that you can skip calling startForeground(). You must call startForeground(). You just have five seconds in which to do so. My guess is that this is to avoid an avenue of abuse for startForegroundService().
Related
I want to reproduce a scenario where android system kills the service.
In service class I'm posting foreground service notification from onCreate and returning START_REDELIVER_INTENT from onStartCommand method. Below exception I'm getting for some of devices.
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
As per code, it shouldn't crash as I am posting foreground service notification from onCreate and cancelling that notification on service onDestroy. The only thing I'm guessing that might possible at some moment android system kills the service and due to that notification get cancelled automatically and service get restarted, and this time onCreate may not get called. But on the other side i'm also not sure whether this time(system kill service) onCreate will get called or not, if that get call then it is impossible to get the above exception.
Try to use a "Terminate" button, it placed in the bottom pane in android studio on the "Run" tab, it looks like a red circle with cross.
After updating my app to target API 27 (previously 25) I'm encountering many ANR's from users, which I can't reproduce. They seem related to the Oreo background execution limits, with the ANR message
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{73bc351 u0 com.xxx.xxxx/.player.PlayFileService}
However I do not call Context.startForegroundService() anywhere in my code. What are some reasons this ANR could be generated that are not a result of a direct call to this method?
In my case, even though I didn't call Context.startForegroundService() directly, it was being called because my music app would go into the background and the service would be destroyed by the system. Then, when the user pressed a media button to resume playback after a couple minutes, the service would get restarted by the system, with that call since the app was in the background. I did call startForeground() eventually but it was after a bunch of configuration. I added a call to startForeground() at the beginning of onCreate() of my service with a blank notification and all my ANR's have disappeared.
Based on the documentation:
Prior to Android 8.0, the usual way to create a foreground service was
to create a background service, then promote that service to the
foreground. With Android 8.0, there is a complication; the system
doesn't allow a background app to create a background service. For
this reason, Android 8.0 introduces the new method
startForegroundService() to start a new service in the foreground.
After the system has created the service, the app has five seconds to
call the service's startForeground() method to show the new service's
user-visible notification. If the app does not call startForeground()
within the time limit, the system stops the service and declares the
app to be ANR
You can follow this SO which describes the approach to properly start the foreground service with Notification Channel.
I'm trying to start an IntentService within my BOOT_COMPLETED receiver, but in Android O (API 26) I get:
java.lang.RuntimeException:
java.lang.IllegalStateException:
Not allowed to start service Intent { act=intent.action.update cmp=packageName.services.OwnService }:
app is in background
(Message is in one line, but this way it's easier readable)
How can I do this the correct way?
Here are some options that I outlined in a blog post:
Workaround #1: startForegroundService()
Your BroadcastReceiver that receives the ACTION_BOOT_COMPLETED broadcast
could call startForegroundService() instead of startService() when on Android
8.0+:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
public class OnBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i=new Intent(context, TestIntentService.class);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
context.startForegroundService(i);
}
else {
context.startService(i);
}
}
}
Note that this works, to an extent, even if your service does not actually
ever call startForeground(). You are given a window of time to get around
to calling startForeground(), "comparable to the ANR interval to do this".
If your work is longer than a millisecond but less than a few seconds,
you could skip the Notification and the startForeground() call. However,
you will get an error in LogCat:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.commonsware.myapplication, PID: 5991
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Of course, if you do not mind having a Notification briefly, you are welcome
to use startForeground() as Android expects you to, in which case you can
do background work normally, albeit with an entry showing up in the user's notification
shade.
Workaround #2: goAsync()
BroadcastReceiver has offered goAsync() since API Level 11. This allows your
receiver to do work off the main application thread, so you could get rid of the
IntentService entirely and move your code into the BroadcastReceiver.
You still only have the ANR
timeout period to work with, but you will not be tying up your main application
thread. This is better than the first workaround, insofar as it has the same
time limitation but avoids the nasty error. However, it does require some amount
of rework.
Workaround #3: JobScheduler
If your work will take more than a few seconds and you want to avoid the
Notification, you could modify your code to implement a JobService and
work with JobScheduler. This has the added advantage of only giving you
control when other criteria are met (e.g., there is a usable Internet
connection). However, not only does this require a rewrite, but JobScheduler
is only available on Android 5.0+, so if your minSdkVersion is less than 21,
you will need some other solution on the older devices.
UPDATE: Eugen Pechanec pointed out JobIntentService,
which is an interesting JobService/IntentService mashup.
You may want to check the following section of the Android O behaviour changes documentation https://developer.android.com/preview/features/background.html#services
It now limits when the app is able to start background services.
I have an IntentService which is used to save [potentially large] files. I initially had a problem where the service would die mid-save if the app was killed. Starting the Service in foreground during a save solved this problem for the most part.
Here is the problem: If the app has been killed while a file is being saved, when I call stopForeground (when the save is complete), the service crashes, indicated in Logcat:
06-23 16:47:25.266: W/ActivityManager(523): Scheduling restart of crashed service...
I have verified that nothing after the call to stopForeground is executed.
It's very possible for me to move my code around a bit, so that this doesn't really cause any problems, but I don't like allowing the service to crash just because there are no consequences...
Because there is no problem at all when the app is still running, my only guess is that it has something to do with the context used to start the service no longer existing. I have tried using both the activity and application contexts, and have also tried running the service in a separate process from the rest of the app. All attempts had the same result.
Am I overlooking something? Thanks!
IIUC, there should only be one instance of a given Android service, it is a singleton.
However, my service gets instantiated multiple times, although I
do nothing for it.
When the service crashes (for example when I uninstall the app through adb), it
gets scheduled for restart ("Scheduling restart of crashed service.. "). I
understand this is an effect of the service being sticky.
After that, when my app starts, it calls startService() and bindService(), and
the service gets appropriately started and bound. But the service is then
reinstantiated and onCreate() is called repeatedly, as many times it was
scheduled for restart.
Each instance then wait for clients to bind and register, but onBind() is only
called in the "main" service instance. The additional instances wait a bit for
client to bind, and since that doesn't happen, they call stopSelf().
But stopSelf() has absolutely no effect in these "dead" instances, onDestroy()
is never called.
The "main" service instance does work as expected, and when it decides to call
stopSelf(), onDestroy() is indeed called.
Worse, all these dead instances accumulate, they never gets destroyed.
Therefore, their only possible end is a crash (which happen every time I
launch/install through adb), and thus scheduled restart.
So that in the end I get many of these dead instances, which are restarted
progressively once by minute approximately.
Does anyone know what's going on?
I got similar behavior if I use eclipse to restart an app with a remote service. According to logcat, system consider the killed service had a crash and tried to restart the service. At the same time, the service has been restarted with the restarted app. For some unknown reason, Android system does not realize there is already a running service, and tries to start a new one.
It happens several times on Optimus one, Galaxy tab, and EVO 3D. It is fine with Nexus one.
Because I haven't seen your code, this is just a guess: Maybe you have a memory leak that prevents the service from destroying properly. That's the only reason I could think of to get multiple instances of service. For example, if you service is holding on to some object that also have a reference to your service. It happens a lot with inner classes.
Check out this video from Google I/O to see if this problem applies to your services and how to find it: http://www.youtube.com/watch?v=_CruQY55HOk&feature=player_embedded
if you use the section to be excecuted in onstart() . if ur starting the service by onclick button or like clicking on icon multiple time means ,what it will do is if service is already running means ,it will go to onstart(),so the method is excecuting again and again its not that service is starting multiple times .... ur method is running for multiple time ,This i told accornding to my guess may be exact code will be Explaind properlly
if your app exit on crash or kill the process it belongs to like System.exit(), it will start after your app exit or start if your service is running in the same process with Application.
Because you kill the process, and Android detect your service should not stop, so Android restart it for you after your app exit. And why service start again after app restart, I think it is Android's bug, it reallocate a new process to your app instead of using the process allocate to your service.
So, how to solve this problem?
just set the attribute android:process=":background"(whatever you want here, starts with :) to your service node in AndroidManifest.xml. hope it helps you.