Android: can local Service be killed by OS independently of the application? - android

I used to think that Android OS is only capable of killing the entire processes of applications, but recently I've been told that, under some conditions, OS can also kill started Service while keeping the Application intact.
So, my questions is: suppose I start (using startService) a local Service in the same process as the rest of my Android application, can this Service be killed by OS independently of the rest of the app (i.e. Service is killed and destroyed, but Application object remains intact)?
If such a scenario is possible, what conditions affect the probability of my Service being killed? Can I prevent this from happening?
Please support your answers with references and/or "prove of concept" code snippets.

I've never heard that Android could destroy particular component of process instead of whole process and never observed this in practice. Instead Android analyzes state of your application components to decide whether your process may be killed to reclaim a memory. Check the documentation - Processes and Threads for details - documentation says nothing about destroying particular components.
Besides, there was a good article Who lives and who dies and the author explicitly stands that Android only kills processes, not components, but, unfortunately, without evolving this topic.
By the way, where did you read/hear about these certain circumstances under which Service may be killed independently of entire process?

Service is independent to Application. There are two ways to handle Service be killed
START_STICKY
If you return START_STICKY in onStartCommand(), system will try to re-create your service after it is killed. Same intent will be passed.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
Foreground Service
A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory.
Calls startForeground() in onStartCommand() to start a Service at foreground but a notification for the status bar will be shown
Notification notification = new Notification(R.drawable.icon,
getText(R.string.ticker_text), System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

Related

Service is killed in sleep mode.Why?

I've read just about every Stackoverflow answer that exists on this topic, but none of them worked.
Goal: Keep my service running 24/7, all the time
Problem: Whenever my device is on sleep mode for an hour or more, the service is killed
What I've tried to fix it:
Returning START_STICKY from onStartCommand() and using startForeground()
public int onStartCommand(Intent intent, int flags, int startId) {
notification = makeStickyNotification(); //I've simplified the irrelevant code, obviously this would be a real notification I build
startForeground(1234, notification);
return START_STICKY;
}
This works fine, and it even restarts my service whenever the device is low on memory, but it is not enough to fix the problem that occurs when my device goes to sleep for a while.
Using Alarm Manager in onCreate() of my Activity and in onStartCommand() of my Service to call a Broadcast Receiver that calls my service
Intent ll24 = new Intent(this, AlarmReceiver.class);
PendingIntent recurringLl24 = PendingIntent.getBroadcast(this, 0, ll24, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000*60, recurringLl24); // Every minute
This helps keep my service active, but again, doesn't solve my problem
Using Schedule Task Executor to keep it alive
if (scheduleTaskExecutor == null) {
scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
scheduleTaskExecutor.scheduleAtFixedRate(new mainTask(), 0, 1, TimeUnit.SECONDS);
}
...
class mainTask implements Runnable {
public void run() {
// 1 Second Timer
}
}
This also just keeps the service active but doesn't keep it alive after a long sleep.
Separate task Manifest
android:launchMode="singleTop"
This did nothing
How can I (1) test this issue without having to put my phone to sleep and check every hour and (2) keep my service running despite the device going to sleep?
Your service was killed by Doze or Standby mode of Android. That was introduced in Android 6.0 (API level 23).
Doze restrictions
The following restrictions apply to your apps while in Doze:
Network access is suspended.
The system ignores wake locks.
Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
The system does not perform Wi-Fi scans.
The system does not allow sync adapters to run. The system does not allow JobScheduler to run.
So system ignored your Alarm Clocks, Scheduler, etc.
In Android Oreo release Android defined limits to background services.
To improve the user experience, Android 8.0 (API level 26) imposes
limitations on what apps can do while running in the background.
Still if app need to run its service always, then we can create foreground service.
Background Service Limitations: While an app is idle, there are limits
to its use of background services. This does not apply to foreground
services, which are more noticeable to the user.
So create a foreground service. In which you will put a notification for user while your service is running. See this answer (There are many others)
Now what if you don't want a notification for your service. A solution is for that.
You can create some periodic task that will start your service, service will do its work and stops itself. By this your app will not be considered battery draining.
You can create periodic task with Alarm Manager, Job Scheduler, Evernote-Jobs or Work Manager.
Instead of telling pros & cons of each one. I just tell you best. Work manager is best solution for periodic tasks. Which was introduced with Android Architecture Component.
Unlike Job-Scheduler(only >21 API) it will work for all versions.
Also it starts work after a Doze-Standby mode.
Make a Android Boot Receiver for scheduling service after device boot.
I created forever running service with Work-Manager, that is working perfectly.
The murder mystery has been solved, and I know what killed my service. Here's what I did:
After I realized that startsticky, startforeground, alarmmanager, scheduleTaskExecutor, and even wakelock were unable to save my service, I realized the murderer couldn't be the Android system, because I had taken every measure possible to prevent the system from killing my service and it still would get killed.
I realized I needed to look for another suspect, since the service wasn't dying because of the system. For that, I had to run an investigation. I ran the following command:
adb shell dumpsys activity processes > tmp.txt
This would give me a detailed log of all the processes running and their system priorities. Essentially, tmp.txt would be the detective in this murder mystery.
I looked through the file with lots of detail. It looked like my service was prioritized properly by the system:
Proc #31: adj=prcp /FS trm= 0 2205:servicename.service/uID (fg-service)
The above line indicates the exact priority of a process running on the Android device. adj=prcp means the service is a visible foreground service.
At this point, I realized that my service must be encountering some error a couple hours after running, so I let it run and die. After it died, I produced a dumpsys again to examine the error:
At this point, my service wasn't listed as a task in the tmp.txt file. Excited, I scrolled to the bottom of the dumpsys and solved the mystery!
com.curlybrace.ruchir.appName.MyService$2.onForeground(MyService.java:199)
at com.rvalerio.fgchecker.AppChecker$2.run(AppChecker.java:118)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
The stack trace that caused the killing of my service was displayed right there! Essentially, a variable that would check for the foreground app being used would become null after a few hours of inactivity, which would cause an exception, and kill the service!
Key Takeaways:
If your service is getting killed, and you've done everything you can to make sure that it shouldn't be killed, perform a dumpsys and examine the nitty gritty of your device's activity process. I guarantee you will find the issue that way.
I still would like to have the bounty awarded to #Khemraj since his answer could be a great solution for someone who hasn't started their service properly. However, I am accepting this answer since it is the solution that actually fixed the issue.
onDestroy() is really unreliable and won't be called often that you want. Same for onLowMemory() callbacks. There is no way to take a guaranteed callback if android decides to kill your process or if user decides to Force Stop your app.
That's normal that than user device go to sleep mode, your service dies. Read about wakelocks. Try something like that in your service:
In manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
In service:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"tag");
wakeLock.acquire();
But it's rly tricky for user and totally anti-pattern in android world, cuz of battery consumption.
Another option is to trigger service something like every 10 mins. Make pending intent on WakefulBroadcastReceiver(where you can start your service) and schedule it with alarm manager with flag RTC_WAKE_UP
Starting from SDK 26 a Service should have its relative "MainActivity" in foreground OR this Service should be started as in foreground using "startForegroundService()". The "startForeground()" doesn't work as expected if the target SDK is 26+ but need the other way I just explained.
After this you can use following code to Kill and restart the App from scratch (yes, even the Service is killed in this way):
Intent mStartActivity = new Intent(context, StartActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(context, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
Doze mode kills services to save battery. Only valid solution for you is to create a foreground service in Oreo and above.
https://developer.android.com/about/versions/oreo/background

How to run a thread in the background after the app is killed

I want to provide the user with toast notifications every 'x' minutes, I tried to do this with the help of service, but when the application was killed, the service stops.
The same issue occurs with intent Service as well, what should I be doing in order for me to keep a thread/service in memory even after the application is killed?
The terms of your question are a bit confusing :
the application lies in a process. If the process is killed, then everything running in that process is killed.
if you want something to survive that process's death, you should use a second process and run the thing to survive inside it.
a service can be run in its own process, looks like a good choice here. Look at android:process attribute in the service tag : http://developer.android.com/guide/topics/manifest/service-element.html
But what you want to do is maybe simpler : set a repeating task. For this, you could use the alarm manager.
You can, for instance :
provide the alarm manager with a pending intent
the pending intent will trigger a service of your own
the service will we waked up, then run. This has the advantage of not letting your service always run and count time to know when it has to wake up (which would drain battery). Here the alarm manager will wake it up when needed, your service will just execute its task and die.
If you combine this approach with the first part of that answer, running your service in a different process, then you can achieve something that's really light weight for the Android device : only your service (in its own process) will wake up at given interval, and the application's process will not be launched by this alarm, but only the service's process.
And about toast notifications, yes, a service is a good place to do it, but the notification bar may be more appropriate to display notifications and notify the user that some event took place inside a background service.
Try implementing foreground service. foreground service
Foreground service displays notification and is never stopped until you want.
Implement this code snippet in your service's onCreate
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

Background Service Stopped When Activity Killed Or Stop or force close

My Problem Is When I M Pressing Home Button And Close My App At That Time Background Service stoped And After That It Requires To LOgin Again In App Then Background Service Will Start So How Can I Do Like Whatssapp If App Will Close Or Kiiled Then Also Sevice Can Run In Background.....
I had the same problem. When you swipe an application out of the application tray, the process of the background service is killed.
You can add the following code in your service or see this question
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
What this code does is that it restarts the process of your application once it is killed when your activity is killed.
Its very simple, Just follow the scenarios in below link.
Continue Service even if application is cleared from Recent app
your service and processes (Threads run inside your service) will remain continuous.
Ok, I'm just guessing - really don't want to check all code for your application.
Service can be starter in 2 ways:
Using bindService() what probably you are doing here. It's nice, but means that service will be disposed as soon as the last client unbind it (what you probably doing in some onPause() method.
Using the startService() command. In such case service will run as long as you stop it or system will consider that this service is using to much memory that should be used for some more urgent task (ex: some fat activity)
The quick fix for your issue (if my guesses are right) will be switching service to be run in "startService" mode. If you don't want to play much with your code the best place to put it is onBind() method of your service (just try to start service from itself). Of course this will not start the service but will switch it's mode to the "long running, real background one".
This will not solve all your problems as I mentioned above - service still can be killed by system in order to get more resources. You can prevent it in some ways: if you really want to keep service running, you should consider to use foreground service (google it) that will increase chances of the service to survive. But the best option is just to use service lifecycle, save data if needed and load them on service start, just like you should do with activity. For long running background services there is also option start sticky that will cause service starting after every kill, crash etc.

Android: keeping a background service alive (preventing process death)

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!!!!

How do I keep running a Service the whole time?

I have some process that I would like to run in the background the whole time.
So I made it a Service.
My question is: is there anyway to prevent from the user from killing this service? (even if he uses third party app)
No, it is not possible. It is also a bad idea.
Maybe this can help you:
final Intent intent = new Intent(context, YourService.class);
final PendingIntent pending = PendingIntent.getService(context, 0, intent, 0);
final AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
long interval = 30000;//milliseconds
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(),interval, pending);
This way your service will be receiving regular onStart events from AlarmManager. If your service is stopped it will be restarted. So you may say it will be running infinitely.
More complete sample can be found in Photostream sample application http://code.google.com/p/apps-for-android/.
•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.)
Send a broadcast in the onDestory method of the service, restart the service in the onReceive method the the broadcast receiver.
But make sure the resources your service are under control
See: http://developer.android.com/reference/android/app/Service.html#ProcessLifecycle

Categories

Resources