My app currently uses a background service to communicate (Bluetooth) with a physical device. (I manufacture and sell the physical device.) The app sends a command to the device every 500ms. The user starts this process and it must run until the user stops it. While the app is active, results of the process are sent to the app. This process needs to run even if the app is not active. (i.e. they take a phone call, search the web.) Once the app becomes active again, the state of the process is synced with the app. The process can run anywhere from a few minutes to many hours. (Yes, the user would need to plug in if they want to run the process for 99hrs.) Most users run it for 2-15min. All is fine for now, but with API 26, it looks like this architecture is no longer allowed. One migration option is to move to a foreground service. However, I find the documentation to be unclear on how foreground services work. Does the foreground service continue to run with the app is not active? (i.e. it has gone through onPause.) If so, how is this any different than a background service? Is there better documentation on how the foreground service works. (My web searches have not turned up anything significant.) Alos, the API 26 documentation does not say if the app is bonded to the background service if the new limitations still apply. Do they?
Thanks,
Stan
A Foreground Service is a Service that you put in the foreground state, that means, the system will not kill the process if it needs CPU or if your app is closed.
First you have 3 kinds of Services:
Started Services (runs in the UI thread)
IntentService (runs in its own thread) (See Services vs IntentServices)
Bound Services (runs as long as there's one activity active that bound it)
As said above, if you close your app, a Bound Service will be closed too, it is launched by bindService().
IntentServices are a subtype of Service which simplify a "work queue process" for incoming intents, i.e it handles incoming intents one by one within a queue, as said in the IntentService description. It has a default implementation and is launched by startService(). It is mainly for asynchronous tasks.
A Started Service is a Service started by a component, and continue to live until stopService() is called or your app is closed.
Using a Foreground Service makes your Service persistent. You have to call startForeground() inside your service. It will still run until you stop your Service, e.g with stopSelf() or stopService();
Note that onStartCommand() will be triggered each time you call startService() but onCreate() is triggered only once.
Here is a simple implementation of a Foreground Started Service:
In your Manifest.xml:
<service android:name=".ConnectionService"
android:enabled="true"/>
In MyService.java:
public class MyService extends Service {
// Unique notification identifier
private final static int NOTIFICATION_ID = 95;
private NotificationManager mNotificationManager;
public MyService() { super(); }
#Override
public void onCreate() {
// Initialize notification
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
// Build your notification here
mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
mBuilder.setSmallIcon(R.mipmap.ic_small_icon);
mBuilder.setContentTitle("MyService");
mBuilder.setContentText("The Service is currently running");
// Launch notification
startForeground(NOTIFICATION_ID, mBuilder.build());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Handle startService() if you need to
// for exmple if you are passing data in your intent
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
// Remove the notification when the service is stopped
mNotificationManager.cancel(NOTIFICATION_ID);
}
}
Finally just call startService().
Forground service is new to me but it looks like a service that has an icon in the status bar so it kind of does have a ui. Have you looked into jobinfo? seems to be a way to run jobs in the background. If you want your service to start on boot complete this article may help Finally and this may be a long shot, on an android device go to settings>application and pick one of the installed applications. You will find a screen pops up because the programmer overrode android.accounts.AccountAuthenticator action. In other words the system started an activity by other than the Launcher intent. In the same way the system must call an intent you can override when bluetooth connects perhaps android.bluetooth.device.action.FOUND check this out
Related
We have an application that runs almost forever with a foreground service, while using a notification on the system tray, which is the normal initialization. The app simply depends on this service. On every device we tested, the service keeps running even the task is removed, but on Xiaomi devices, after swiping from the recents, it suddenly stops, then starts again depending on how ActivityManager decides to re-open the service. We're getting logs from Xiaomi devices (Xiaomi MI9 on this case) such as:
Scheduling the restart of the crashed service: com.example.myapp/.MyService in 1000ms
This shouldn't happen, but it does. And every time we open the app and close it from the recents, the 1000ms part keeps increasing to 4000ms, 16000ms, 64000ms and so on. I don't think it has a limit, and 64 seconds is already too long for a foreground service to restart that is crucial for the app. So, I'm searching for methods to add our app as an exception or something, but the only thing I found is this: https://dontkillmyapp.com/xiaomi
If the app is killed with the X button on the recents screen, then that's even worse as I've noticed the device kills all the services and schedules them to restart in 10 second gaps. I think ours were scheduled to start 3 hours after, which destroys the purpose of the app.
The current solution that we're using is to warn the user about this issue and redirect to this link, in order to add our app to exceptions, enabling Autostart and so on. But, we're aware that almost nobody will do this, so we're looking for a solution that can be achieved programmatically.
A little code that demonstrates how we register the service to manifest and how we start it. (The demonstration is simpler than the original, but describes the main logic.)
Manifest part:
<service android:name=".MyService"
android:stopWithTask="false" />
Starting the service part:
// Starts the service as foreground.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
context.startForegroundService(new Intent(context, MyService.class));
else
context.startService(new Intent(context, MyService.class));
Posting the notification part:
// Post the notification on both onCreate and
// onStartCommand so we can only hope that
// the app won't throw the unavoidable exception
// which occurs 5 seconds after calling
// Context.startForegroundService().
#Override
public void onCreate()
{
super.onCreate();
// Handles how the notification
// is shown, content is not important.
// Calls startForeground inside.
showNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
showNotification();
// Some other service code that is irrelevant
// Return START_STICKY so we can ensure that if the
// service dies for some reason, it should start back.
return START_STICKY;
}
I think everything is done correctly as this only happens on Xiaomi devices, but we couldn't find a solution about keeping this service alive. Is anyone else experiencing the same thing? How should we proceed so our service doesn't die? Thanks for all the help.
Goto Settings->Permissions->AutoStart and then select your app
I have a location service which I want to run at all times when the app is in the foreground, or in the background, but to stop when the app is closed (removed from the app tray)
My solution has been to start the service using START_NOT_STICKY and this seems to work, but I'm concerned by what the service documentation says about this command
START_NOT_STICKY says that, after returning from onStartCreated(), if the process is killed with no remaining start commands to deliver, then the service will be stopped instead of restarted. This makes a lot more sense for services that are intended to only run while executing commands sent to them. For example, a service may be started every 15 minutes from an alarm to poll some network state. If it gets killed while doing that work, it would be best to just let it be stopped and get started the next time the alarm fires.
So it seems that Android may kill off services when memory is low, and if using START_NOT_STICKY the service will not be restarted.
I tried using START_STICKY but this keeps the service running even after the app is closed.
What can I do to keep the service running at all times while the app is in the foreground or background, and stop after being closed, but without worrying about Android terminating it while the app is running?
Code here if it matters:
#Override
public int onStartCommand(Intent intent, int flags, int startId){
if (intent != null) {
extras = intent.getExtras();
// takes the messenger object and makes it local so when the messagereceiver sends an intent here, it won't overwrite the extras object
// and get rid of the messenger. Otherwise, getting an update from the notification controls would null out the messenger object
if (intent.hasExtra("MESSENGER")) {
Timber.e("MESSENGER ");
messenger = (Messenger) extras.get("MESSENGER");
}
}
return START_NOT_STICKY;
}
What can I do to keep the service running at all times while the app is in the foreground or background, and stop after being closed, but without worrying about Android terminating it while the app is running?
I'm not sure what "app tray" you're referring to or what exactly you mean by "closed" (Android apps are not things that are "closed", per se.
But, from your description, I'd think you want to do something like:
Start your Service when the user starts your app and bind to while the activity is in the foreground
If your activity is paused (or stopped), unbind from the service and start a foreground notification to keep the service alive and the user aware that it's still running
Instead of trying to detect when the app is "closed", which you can't really do, attach a "cancel" action to the foreground notification so the user can cancel it whenever they want
If that doesn't solve your issue, please elaborate on your use case and why you want to do this. I or others may be able to provide more / better / alternate suggestions with more specifics about what you're actually ultimately trying to achieve.
Hope that helps!
I would like to start my foreground service when my application is closed.
I tryed OnStop() but it's not a good idea for me because it can trigger multiple times and i which it to run only one instance.
I tryed OnDestroy() but it's simply doesn't trigger since i'm only using one activity in my whole app and most of time it is being kill with the SWIPE.
Is there a way i can detect when my application being kill or close ?
Thanks!
Only one instance of the service will run no matter how many times you start it. Each time a client starts the service the onStartCommand method fires. return Service.START_STICKY; to have your service stay running in the back ground after your app exits. But be warned if things get busy and the phone needs memory your service will be killed and you'll have to restart it like #Onur suggests with a conservative periodic AlarmManager intent.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// the service is started so after all clients are unbound it stays
// running
return Service.START_STICKY;
}
You can add your services description in manifest.xml stopWithTask="false" and in your sevice override the onTaskRemoved (Intent rootIntent) to know when activity that started the service is stopped for API level 14 and later.
Or you can set an alarm for some periods to check if your application is still running using AlarmManager. You should be careful with this tho, because it might consume battery based on the period you choose.
Here is my Service
public class SService extends Service {
public void onCreate() {
super.onCreate();
someTask();
}
public int onStartCommand(Intent intent, int flags, int startId) {
someTask();
return START_STICKY;
}
public IBinder onBind(Intent intent) {
return null;
}
After force stop of app (Settings->Application->Force Stop App) my Service doesn't run. How to solve it?
As per the Android document
Starting from Android 3.1, the system's package manager keeps track of applications that
are in a stopped state and provides a means of controlling their launch from background
processes and other applications.
Note that an application's stopped state is not the same as an Activity's stopped
state. The system manages those two stopped states separately.
Note that the system adds FLAG_EXCLUDE_STOPPED_PACKAGES to all broadcast intents. It
does this to prevent broadcasts from background services from inadvertently or unnecessarily
launching components of stoppped applications. A background service or application can
override this behavior by adding the FLAG_INCLUDE_STOPPED_PACKAGES flag to broadcast intents
that should be allowed to activate stopped applications.
On Force stop of app, Android just kill the process ID. No warnings, callbacks are given to service/activities. As per the Android document, When the app is killed there are chances that it calls onPause().
When I tried in my app, even onPause() was not called.
I think the only way is use to that intent flag and send it from another app as suggested by Chris.
Are you sure that the service isn't restarting? The START_STICKY you put in the return should do the trick some time. It takes some time till the system restart it, you can put a log and wait to make sure it's getting restarted.
I have a service that is defined as:
public class SleepAccelerometerService extends Service implements SensorEventListener
Essentially, I am making an app that monitors accelerometer activity for various reasons while the user sleeps with his or her phone/device on the bed. This is a long-running service that MUST NOT be killed during the night. Depending on how many background apps and periodic processes occur during the night, android sometimes kills off my process, thereby ending my service. Example:
10-04 03:27:41.673: INFO/ActivityManager(1269): Process com.androsz.electricsleep (pid 16223) has died.
10-04 03:27:41.681: INFO/WindowManager(1269): WIN DEATH: Window{45509f98 com.androsz.electricsleep/com.androsz.electricsleep.ui.SleepActivity paused=false}
I do not want to force the user to have 'SleepActivity' or some other activity in my app as the foreground. I can't have my service run periodically, because it is constantly intercepting onSensorChanged.
Any tips? source code is here: http://code.google.com/p/electricsleep/
For Android 2.0 or later you can use the startForeground() method to start your Service in the foreground.
The documentation says the following:
A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
The is primarily intended for when killing the service would be disruptive to the user, e.g. killing a music player service would stop music playing.
You'll need to supply a Notification to the method which is displayed in the Notifications Bar in the Ongoing section.
When you bind your Service to Activity with BIND_AUTO_CREATE your service is being killed just after your Activity is Destroyed and unbound. It does not depend on how you've implemented your Services unBind method it will be still killed.
The other way is to start your Service with startService method from your Activity. This way even if your Activity is destroyed your service won't be destroyed or even paused but you have to pause/destroy it by yourself with stopSelf/stopService when appropriate.
As Dave already pointed out, you could run your Service with foreground priority. But this practice should only be used when it's absolutely necessary, i.e. when it would cause a bad user experience if the Service got killed by Android. This is what the "foreground" really means: Your app is somehow in the foreground and the user would notice it immediately if it's killed (e.g. because it played a song or a video).
In most cases, requesting foreground priority for your Service is contraproductive!
Why is that? When Android decides to kill a Service, it does so because it's short of resources (usually RAM). Based on the different priority classes, Android decides which running processes, and this included services, to terminate in order to free resources. This is a healthy process that you want to happen so that the user has a smooth experience. If you request foreground priority, without a good reason, just to keep your service from being killed, it will most likely cause a bad user experience. Or can you guarantee that your service stays within a minimal resource consumption and has no memory leaks?1
Android provides sticky services to mark services that should be restarted after some grace period if they got killed. This restart usually happens within a few seconds.
Image you want to write an XMPP client for Android. Should you request foreground priority for the Service which contains your XMPP connection? Definitely no, there is absolutely no reason to do so. But you want to use START_STICKY as return flag for your service's onStartCommand method. So that your service is stopped when there is resource pressure and restarted once the situation is back to normal.
1: I am pretty sure that many Android apps have memory leaks. It something the casual (desktop) programmer doesn't care that much about.
I had a similar issue. On some devices after a while Android kills my service and even startForeground() does not help. And my customer does not like this issue. My solution is to use AlarmManager class to make sure that the service is running when it's necessary. I use AlarmManager to create a kind of watchdog timer. It checks from time to time if the service should be running and restart it.
Also I use SharedPreferences to keep the flag whether the service should be running.
Creating/dismissing my watchdog timer:
void setServiceWatchdogTimer(boolean set, int timeout)
{
Intent intent;
PendingIntent alarmIntent;
intent = new Intent(); // forms and creates appropriate Intent and pass it to AlarmManager
intent.setAction(ACTION_WATCHDOG_OF_SERVICE);
intent.setClass(this, WatchDogServiceReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am=(AlarmManager)getSystemService(Context.ALARM_SERVICE);
if(set)
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + timeout, alarmIntent);
else
am.cancel(alarmIntent);
}
Receiving and processing the intent from the watchdog timer:
/** this class processes the intent and
* checks whether the service should be running
*/
public static class WatchDogServiceReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(ACTION_WATCHDOG_OF_SERVICE))
{
// check your flag and
// restart your service if it's necessary
setServiceWatchdogTimer(true, 60000*5); // restart the watchdogtimer
}
}
}
Indeed I use WakefulBroadcastReceiver instead of BroadcastReceiver. I gave you the code with BroadcastReceiver just to simplify it.
http://developer.android.com/reference/android/content/Context.html#BIND_ABOVE_CLIENT
public static final int BIND_ABOVE_CLIENT -- Added in API level 14
Flag for bindService(Intent, ServiceConnection, int): indicates that the client application binding to this service considers the service to be more important than the app itself. When set, the platform will try to have the out of memory killer kill the app before it kills the service it is bound to, though this is not guaranteed to be the case.
Other flags of the same group are: BIND_ADJUST_WITH_ACTIVITY, BIND_AUTO_CREATE, BIND_IMPORTANT, BIND_NOT_FOREGROUND, BIND_WAIVE_PRIORITY.
Note that the meaning of BIND_AUTO_CREATE has changed in ICS, and
old applications that don't specify BIND_AUTO_CREATE will automatically have the flags BIND_WAIVE_PRIORITY and BIND_ADJUST_WITH_ACTIVITY set for them.
Keep your service footprint small, this reduces the probability of Android closing your application. You can't prevent it from being killed because if you could then people could easily create persistent spyware
I'm working on an app and face issue of killing my service by on app kill. I researched on google and found that I have to make it foreground. following is the code:
public class UpdateLocationAndPrayerTimes extends Service {
Context context;
#Override
public void onCreate() {
super.onCreate();
context = this;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
StartForground();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void StartForground() {
LocationChangeDetector locationChangeDetector = new LocationChangeDetector(context);
locationChangeDetector.getLatAndLong();
Notification notification = new NotificationCompat.Builder(this)
.setOngoing(false)
.setSmallIcon(android.R.color.transparent)
//.setSmallIcon(R.drawable.picture)
.build();
startForeground(101, notification);
}
}
hops that it may helps!!!!