It seems Android in recent version have introduced multiple restrictions on running services in the Background, which of course it good news for battery life of our devices. My goal is to create an app which adheres to this by only running a service as long as the User is interacting with the app (which seems to be what they are aiming for). But it's anything but clear to me how you can implement this properly. My requirements are as follows:
The Service should be started as soon as any Activity becomes visible to the user.
The Service should stay uninterrupted in the running state while the user is interacting with the app (browsing between activities).
When the UI (regardless of what activity was active) is sent to the background, the Service should run for 2-3 seconds and then stop itself. The 2-3 seconds are needed for a clean shutdown of the service.
The service can be started via a Push message when the app is in the background (or closed), in order to handle incoming events at any time. The service then registers to the Remote Server, and checks for updates. If there are updates, a notification is given to the user. Then the service once more shuts back down after 2-3 seconds of inactivity.
To me, it seems a Bound Service is what is intended to be used. But it's not clear to me how my requirements will fit with the Bound Service model. Is there anyone who have any experience with this, who can point me in the right direction?
EDIT: The "Service" in this case is a Local, In-Process service, which is not intended to be accessed externally.
(This answer presumes a local, "in-process" Service, which is no doubt what you intend to use.)
For your use case, you actually use a combination of techniques to keep the Service running.
Use the "bound Service model" to keep the Service around while any one of your Activities are visible. It's simple enough; call bindService() in Activity.onStart(), and unbindService() in Activity.onStop(). If you're worried about the Service being destroyed in the brief moment of transition between two of your Activities, don't be; Android is smart enough to wait for the lifecycle changes of different application components to "settle" before it decides a Service is unreferenced/unneeded.
You should use the BIND_AUTO_CREATE flag for all your bindService() calls. Keep in mind that the Service isn't created immediately upon calling bindService(); it takes a few milliseconds, and you must be careful to return control to the framework, by returning from whatever lifecycle method (e.g., onStart()) you are currently in. Only then will you get a call to onServiceConnected().
You'll need to manually keep track of how many Activities are bound to your Service, in order to determine when to begin your 2-3 second cleanup logic. See this answer for a valid approach. Don't worry about the Service being destroyed synchronously during your last unbindService() call -- just as with bindService(), the actual lifecycle state change is "delayed."
Now the question is, how do you keep the Service alive for this extra 2-3 seconds, at this point (the point where you've determined the number of open Activities has dropped to 0)? Well, you can simply call startService(). You can even call it from a method in your Service subclass; as long as you have a valid Context available, it doesn't really matter. startService() indicates to the system that you want to keep the Service around, irrespective of how many Activities (or other clients) might be bound to it. In this case, the Service won't be restarted -- it's already running!
Once your cleanup is complete, you can call stopService() or, better yet, stopSelf(). That effectively cancels the startService() call, and tells the OS, "I'm done". Expect a call to Service.onDestroy() shortly thereafter.
Keep in mind that one of your Activities might pop up asynchronously, and re-bind to the Service, before cleanup completes. It is an edge case, but one that is easily handled. The Service will only be destroyed when both these conditions are true: 1.) No clients are binding/bound, and 2.) no un-cancelled calls to startService() exist.
Note that on Oreo and later, the system can be quite aggressive about killing apps with background Services. According to this doc, interacting with the user puts you on the whitelist for "several minutes", so I think 2-3 seconds is going to be OK. Similarly, if you're handling a "high-priority FCM message" (which is what I assume you mean by "push" message), you'll be placed on the whitelist, and allowed another few minutes in which to execute the Service (this time using the startService()/stopSelf() approach).
Related
I'm fighting with the Android desire of killing everything which isn't active on the screen. My problem in few words:
I have a microcontroller which communicates with a processor on which Android runs;
the processor must keep active a watchdog on the microcontroller, resetting periodically (every one second) one of its registers; an application, say App B, accomplishes this duty;
on the processor I can be sure about the persistent existence of another application, say App A (or, however, if App A dies App B can die too because the system is compromised) which for now does nothing, in the future will accomplish other duties.
Which is the best way to implement App B?
I tried the following solution: App B contains a Bound Service, say Service A, to which App A can bind on; Service A starts a thread, say Thread A, which periodically resets the microcontroller watchdog. Thread A is launched when app A sends a command to Service A (e.g. START_WATCHDOG).
In my idea, Service A lives until App A lives (thanks to the binding), and so the process to which Service A belongs lives, and so also Thread A.
Unfortunately, from tests I see that sometimes (in a sporadic manner), after some time (sporadic time, too), with almost no work running on the system (except for App A, Service A and Thread A) the system kills Service A process, and so Thread A stops and the watchdog elapses.
When Service A dies, it is restarted (because it is a Bound Service and App A is still running) but, for now, I don't save the current state of Service (which simply consists on the START_WATCHDOG command arrival or not) and this is the reason for which the watchdog elapses.
So, I've got several questions about my solution:
is it ok and I simply need to save the current state of Service A in order to restore it when restarted?
should I discover better the reasons for which Service A, or better its process, is killed?
is there a better solution for my problem?
Thank you very much to everyone who will spend some time to help me.
Being not sure about periods in which your service runs you can try these:
Use foreground service. However, you might need to acquire a wakelock within your service start point if you need cpu in long time. Plus, a notification needs to be shown on phone status bar.
Use WorkManager-new api part of jetpack simplifying the use of alarm managers and jobschedulers- to schedule your tasks periodically. However if your frequency is higher than 1 per 5-10minute then you will need to take care of doze mode. If phone gets into doze, your tasks might be delayed till maintenance periods. A trick to apply here might be starting a foreground service when you catch activation of doze mode and return back to Workmanager logic in deactivation(if you don't want user to see the foreground service's notification). Do whatever you want in the foreground service like.
Use Firebase Cloud Messaging to push notification from your server to your users periodically for you to have a small amount of time to do work in background. When notification comes, OS grants you an interval to run a task.
Use Work manager it is easy to implement.
Since threads persist past the lifetime of the activity that spawn them, I can just put whatever background work I need to do on HandlerThreads for example, no need for a service. Also they will keep running when the app in in the background bypassing the new Oreo restrictions.
Am I missing something here?
Also, ever since the introduction of Doze mode and the addition of even more restrictions on background work starting Oreo, when exactly should I use a service to do background work? Apart from
scheduling tasks for future conditions, such as WIFI connection, or charging I would then use a JobScheduler. But even that can be handled through a BroadcastReceiver...
Also they will keep running when the app in in the background bypassing the new Oreo restrictions.
That isn't quite right. It's true that background threads will continue to execute for as long as your app is alive. The problem is, your app might not be alive for very long! A Service is used to indicate to the operating system, "I don't want to get torn down; I still have useful work I have to do".
From the docs:
...[A Service represents] either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
and
It is not a means itself to do work off of the main thread
Ultimately, when Android is deciding whether or not to keep your App around, it doesn't care about the number of threads you have running, the number of CountDownTimers that haven't finished yet, how many Runnables you have waiting in the queue, etc. It cares about whether or not you have any active application components. Is an Activity visible? Great, stick around. Is a Service started? Also great. None of the above? Maybe it's time to terminate the app.
So this also answers the question, "when exactly should I use a service to do background work?" As mentioned, a Service won't do the work for you, it'll just help you stay alive. You can try to kick off a thread in a BroadcastReceiver (note that most implicit broadcasts no longer work post-Oreo), but as soon as you return from onReceive(), your app is likely to be killed -- unless you have a Service going, too.
ADDITIONAL POST-OREO CAVEATS
Note that a Service is likely only going to help your app stay alive for "several minutes" after the app leaves the foreground (docs). The only way I am aware of to get around this is to get back into the foreground by making your Service a "foreground service."
Additionally, if you need to ensure the device remains awake until your work is completed, you'll need a component in the foreground. That is, you can still do that work in the "background" (in the sense of being "off-screen"), but you'd need a "foreground Service" (icon in the action bar). Otherwise, Doze will apply, and that tends to inhibit any WakeLocks your app is using.
I have an activity that contains an Instance of FileObserver. I start watching in onCreate and stop watching in onDestroy of the activity. So what happens if onEvent is doing some operation and the activity is destroyed (user presses back button)? Does my onEvent continue to finish what it was doing? Basically I am wondering whether onEvent should start a service or handle its business itself.
Does my onEvent continue to finish what it was doing?
At least briefly, yes. FileObserver is not tied to a specific component's lifecycle, like that of an Activity.
However, once your app is no longer in the foreground, your process can be terminated at any point, to free up system RAM for other apps. Android is not going to pay any attention to your FileObserver and its onEvent() processing when this occurs, by default.
If you expect the work to happen quickly — say, under a second — you should be able to keep it where it is.
If, however, the sort of work that you are doing is more substantial, I would consider having a service do the work. Per our prior discussion, while the FileObserver should not be in an IntentService, the work triggered by the FileObserver could be. onEvent() would call startService() to tell the service to go do the work. Services are a signal to the OS that you are actively doing work on behalf of the user, and so your process is more likely to hang around for a bit longer.
Unless the Application is stopped the code in your onEvent will continue to run.
FileObserver.onEvent documentation
This method is invoked on a special FileObserver thread. It runs independently of any threads, so take care to use appropriate synchronization! Consider using post(Runnable) to shift event handling work to the main thread to avoid concurrency problems.
So the only think you need to be concerned with is what exactly you are doing in onEvent. For instance if you are updating UI or interacting with the Activity / Fragment in your onEvent method then this could cause a crash if the Activity goes away.
With that in mind a service will certainly increase the odds that the application does not terminate while you are performing your work.
Service documentation
The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again...
So the bottom line is that a service is more likely to keep your application alive. Event more likely if you call startForeground but in this case you need to be willing to show a notification to the user.
My requirement: Detect and respond to power events. I have an activity which allows the user to set up the responses. The app must keep responding after the UI has gone to the background (either by user action, ie "Home", or by, for example, receiving a phone call).
My analysis:
Use a BroadcastReceiver which accepts ACTION_POWER_DISCONNECTED (and ..CONNECTED)
I have implemented the receiver within the activity, and it works as expected. It continues to work in the background for some time, but eventually stops working because of normal android lifecycle, ie. the OS destroys it.
(Proposed) To keep the receiver running, I follow this recommendation and make it a service, with startForeground.
(Proposed) Because it must interact with the UI, ie, by accepting changes to its settings, it should be a bound service.
The expected problem:
According to the documents a bound service is stopped when all clients unbind. I have only one client (the UI), which will unbind in its onDestroy method. This will be called when client is stopped by the OS, which will eventually happen under normal resource management.
A service is "bound" when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
Questions
Is this analysis correct? ie. Will a bound service, with one UI client, eventually be destroyed when the client is destroyed, as part of normal OS management?
If so, what should I do about it?
Any other tips please :)
Asked as a hypothetical, because there is quite a bit of work setting up the bound service and then proving that it stops as expected. Also, even it it appears to work, I might be doing this wrong.
Why not register the broadcast receiver in your manifest? It will be started and invoked automatically when the power intents are broadcast. Then you don't need to worry about any sort of "keep alive" processing (and you won't need a service unless you need to do some longer processing)
I have an Android app, in which Activities fire long running operations that run in the background. These operations interact with the Activities when done. I'm developing a component that handles the Activity/Long-Running-Task coupling, taking care of activities being destroyed and recreated.
Right now that component is implemented as an Android service. The activities call bindService and use the resulting IBinder to start and track tasks. I decided against using startService, because I prefer the richer API possible through a Java interface.
Now the problem. Activity A start ups, binds to the service and calls serviceApi.runTask(...). Activity A is then destroyed (because the user flips the phone, for instance) and recreated as Activity A'. A' then binds again to the service, announces its existence and everything should be running nicely.
Except that my Service gets destroyed. When Activity A is destroyed, it unbinds from the service. Android sees there are no more clients, and kills the service. When Activity A' is created, the service is created again, and I lose everything the old service had.
The only solution I can see is using a singleton for the service. And then it doesn't really have to be an Android service, just an instance that's accessible to everyone. Is that frowned upon in Android? Is there a better design that fits this problem?
Editted: Even if I call startService and then bind to it, nothing guarantees that the service instance will exist as long as the application is running. Android can kill sticky services if resources are low. Killing the service will cause the application to malfunction, and I can't have that.
Even if I call startService and then bind to it, nothing guarantees that the service instance will exist as long as the application is running.
Correct.
Android can kill sticky services if resources are low.
Also correct. All "sticky" means is that Android might restart the service.
Killing the service will cause the application to malfunction, and I can't have that.
It is impossible to create a service that is guaranteed to run forever. For starters, users can get rid of your service whenever they want, because users detest developers who have pointless services that run forever. Writing everlasting services is necessary only in very few cases; otherwise, it's just sloppy programming.
The only solution I can see is using a singleton for the service. And then it doesn't really have to be an Android service, just an instance that's accessible to everyone. Is that frowned upon in Android?
Singletons (a.k.a., static data members) will go away when the process is terminated. The process will be terminated eventually, particularly if there are no active services and none of your activities is in the foreground..
Call startService and in onStartCommand return START_STICKY. It should keep the service going.
You may also want to look into foreground services:
http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)
Yo have to create persistent service. Refer to this manual.
In a few words - don't call bindService, call startService.