Xiaomi devices are stopping foreground services - android

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

Related

Is there any way to run service continuously?

There are few questions similar to this on Stack Overflow but none of the solutions are working for me
The problem is with only few devices like OnePlus and MI, The service is getting killed as soon as the user swipes away app from recent app.
I read that these OEM'S use some aggressive strategies to kill services. I just want to know is there any way to keep service running or start it as soon as it gets killed.
I need to run a service which will give location continuously (24/7) in background (This app is only for specific people so no worries about battery life).
I've tried:
running foreground service.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
Also in service onCreate method started with notification
#Override
public void onCreate() {
Log.i("Service", "onCreate");
startForeground(NOTIFICATION_ID, getnotification());
}
returning START_STICKY in onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
initLocationClient();
initLocationSyncThread();
return START_STICKY;
}
re-initiating service in onDestroy and onTaskRemoved but they are not getting called.
binding a service
scheduling alarm manager and start service frequently but play store will give warning that our app is using alarm manager too frequently and its a bad practice. And there is now way using workmanager to schedule for less than 15 min and its still not guaranteed to start after 15 min.
So is there any way to keep running a service other than above options?
If you go through THE LINK, you will find:
Unfortunately, some devices implement killing the app from the recents menu as a force stop. Stock Android does not do this. When an app is force stopped, it cannot execute jobs, receive alarms or broadcasts, etc. So unfortunately, it's infeasible for us to address it - the problem lies in the OS and there is no workaround.
It is a known issue. To save battery, many manufacturers force close the app, thus cancelling all the period tasks, alarms, and broadcast receivers etc. Major manufacturers being OnePlus (you have option to toogle), Redmi, Vivo, Oppo, Huwaei.
Each of these devices have AutoStartManagers/AutoLaunch/StartManager type of optimization managers. Which prevent the background activities to start again. You will have to manually ask the user to whitelist your application, so that app can auto start its background processess. Follow THIS and THIS link, for more info.
The methods to add to whitelist for different manufactures are give in this Stack Overflow answer. Even after adding to whitelist, your app might not work because of DOZE Mode, for that you will have to ignore battery otimizations
Also in case you might be wondering, apps like Gmail/Hangout/WhatsApp/Slack/LinkedIn etc. are already whitelisted by these AutoStart Managers. Hence, there is no effect on their background processes. You always receive timely updates & notifications.
Here are few things which helped little .
In AndroidManifest.xml add line android:enabled="true"
<service
android:name=".service.TrackingService"
android:exported="false"
android:enabled="true"
/>
Inside service Add alarm to wake up again after 2 seconds .
#Override
public void onTaskRemoved(Intent rootIntent) {
initAlarm();
super.onTaskRemoved(rootIntent);
}
private void initAlarm() {
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, StartServiceReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() +
2000, alarmIntent);
}
Create a receiver StartServiceReceiver and in it just start service again .
For Mi devices we need to allow a permission inside setting to allows service to start in background
The right way to listen to location on the background of to use a fused location API from play services.
Look at the samples here.
https://github.com/googlesamples/android-play-location?files=1
These API's are power efficient, and I would recommend it too.

Android: Keep service running, stop when app closed (removed from app tray)

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!

Clarification on Android foreground service

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

Start service when the application exit (or is killed)

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.

Is it possible to run my service for indefinite time?

Can I run a background service Indefinitely ? Will android kill my service if i run it for indefinitely ? How Facebook android application keep running in background for a long time ?? please help me to know about it .
You can use for that these features:
1) Auto-restart service after reboot (Start intent after Reboot)
2) Sticky service mode (http://developer.android.com/reference/android/app/Service.html#START_STICKY)
These features both helps to leave your service started all time as possible.
Android will kill your service if it's running out of memory, but you can do a couple of things to recover from it.
The first thing you can try is to use foreground services, a foreground service is a high priority services that won't be killed unless is completely necessary (note that these services increase battery consumption). You can find an example here using compatibility with older devices, otherwise you only need to call startForeground inside your service.
Another thing you can do is to use some flags in your service to restart it when it gets killed by the OS. You can use 2 different flags (depending on which behaviour you want to reproduce).
START_STICKY will restart your service with an empty intent so everytime you have to recover the data you need to run your service.
START_REDELIVER_INTENT in this case your service will be restarted with the last intent information (it could be that you run your service several times with different information when you want different behaviour).
The flags can be used as follows:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Do your service work
return START_STICKY; //or return START_REDELIVER_INTENT;
}
Depending on what you need use one or another.
Hope it helps :)
There's no way to absolutely protect a Service from being killed.
If you return START_STICKY from onStartCommand(), then even if Service is killed, android will try its best to start it again, when resources are free.

Categories

Resources