START_STICKY does not work on Android KitKat - android

One of my apps has a backgrouod service that uses the START_STICKY return code from onStartCommand to automatically restart when the system kills it.
It seems that this is no longer working on Android KitKat.
Is there any solution for this ?
Should I be doing something different on Kitkat to keep the service running ?
Note: There is a similar discussion on the Android-Devlopers group about swiping the app from the recent apps list behaves. Could this two issues be related ?
https://groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac
Edit: Saw that there are open bugs on Android issue tracker:
https://code.google.com/p/android/issues/detail?id=63793
https://code.google.com/p/android/issues/detail?id=63618
Edit2: The same happens even if service is running using startForeground, in a separate process and with the flag android:stopWithTask="false" in the AndroidManifest.xml file...
Edit3: More related bugs on Android issue tracker:
https://code.google.com/p/android/issues/detail?id=62091
https://code.google.com/p/android/issues/detail?id=53313
https://code.google.com/p/android/issues/detail?id=104308
Is there some sort of workaround to get the previous behavior ?

Seems that this is a bug present in Android 4.4, got around it with the following:
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartService = new Intent(getApplicationContext(),
this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(
getApplicationContext(), 1, restartService,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);
}
Found this answer from this post

The problem here appears to not to occur on AOSP based ROMs. That is, I can easily recreate this on a CyanogenMod 11 based ROM, but on an AOSP ROM (and on an Emulator), START_STICKY behaves exactly as I'd expect. That said, I am seeing reports from folks on Nexus 5's that appear to be seeing this behavior, so perhaps it is still an issue in AOSP.
On an emulator and on an AOSP ROM, I see the following from a logcat when I do a 'kill 5838' against the process (as I'd expect):
12-22 18:40:14.237 D/Zygote ( 52): Process 5838 terminated by signal (15)
12-22 18:40:14.247 I/ActivityManager( 362): Process com.xxxx (pid 5838) has died.
12-22 18:40:14.247 W/ActivityManager( 362): Scheduling restart of crashed service com.xxxx/com.xxxx.NotifyingService in 5000ms
12-22 18:40:19.327 I/ActivityManager( 362): Start proc com.xxxx for service xxxx.pro/com.xxxx.NotifyingService: pid=5877 uid=10054 gids={50054, 3003, 3002, 1028}
I see the same restart behavior if I end the task by 'swiping' from the recent tasks list. So this is all good - it means that the core AOSP code is behaving as it has in previous levels.
I am looking at the Cyanogenmod service code to try and figure out why things aren't getting scheduled for restart - no luck yet. It appears that it should reschedule it. Cyanogenmod uses a service map which AOSP doesn't - but unclear whether that is an issue or not (doubtful)
https://github.com/CyanogenMod/android_frameworks_base/blob/cm-11.0/services/java/com/android/server/am/ActiveServices.java#L2092
A rather hackish workaround you can do is to use a similar mechanism as your onTaskRemoved AlarmService to enable an alarm for X minutes later. Then every few minutes while your app is up and running, you can reset the alarm - so it only goes off if things really have been killed and not restarted. This isn't foolproof - using a Handler gives you uptime vs the alarm service which uses realtime, so it's possible for your alarm to trigger even though it was set at a longer time than your 'reset' handler. But if you set an intent extra you can chose to ignore the onStartCommand if your service was already up and running, turning this into a noop.
I'm not a fan of the following hack at all - but it shouldn't do any real harm. If the user does an explicit Force Close, then the alarm manager will destroy any alarms set so that the service won't restart (which is what the user wants).
First, create a helper method that will set an alarm for 20 minutes which will cause onStartCommand to be triggered for your service. Every 2 minutes have a Handler which will reset the 20 minute alarm. If the handler runs within the realtime 20 minutes, the alarm will never go off. The handler isn't guaranteed to run though if the device is asleep (which is good).
private void ensureServiceStaysRunning() {
// KitKat appears to have (in some cases) forgotten how to honor START_STICKY
// and if the service is killed, it doesn't restart. On an emulator & AOSP device, it restarts...
// on my CM device, it does not - WTF? So, we'll make sure it gets back
// up and running in a minimum of 20 minutes. We reset our timer on a handler every
// 2 minutes...but since the handler runs on uptime vs. the alarm which is on realtime,
// it is entirely possible that the alarm doesn't get reset. So - we make it a noop,
// but this will still count against the app as a wakelock when it triggers. Oh well,
// it should never cause a device wakeup. We're also at SDK 19 preferred, so the alarm
// mgr set algorithm is better on memory consumption which is good.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
// A restart intent - this never changes...
final int restartAlarmInterval = 20*60*1000;
final int resetAlarmTimer = 2*60*1000;
final Intent restartIntent = new Intent(this, NotifyingService.class);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
final AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler = new Handler()
{
#Override
public void handleMessage(Message msg) {
// Create a pending intent
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + restartAlarmInterval, pintent);
sendEmptyMessageDelayed(0, resetAlarmTimer);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
}
In your onCreate you can call this method. Also - in your onStartCommand, be sure to ignore this if your service is already up and running. EG:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
if ((intent != null) && (intent.getBooleanExtra("ALARM_RESTART_SERVICE_DIED", false)))
{
Log.d(TAG, "onStartCommand after ALARM_RESTART_SERVICE_DIED");
if (IS_RUNNING)
{
Log.d(TAG, "Service already running - return immediately...");
ensureServiceStaysRunning();
return START_STICKY;
}
}
// Do your other onStartCommand stuff..
return START_STICKY;
}

This is not a 100% working solution but it's the best so far as it almost completely eliminates the problem. So far I integrated this solution along with overriding onTaskRemoved (See this answer) and a keep-alive notification (See this answer).
Additional answers are very appreciated !
After further investigation, it seems that the bug already exists in Jelly Bean and looks like there is a solution for that (At least in my case that seems to work. will keep on testing and update the answer if required).
From what I observed this only happens with services that receive broadcasts set by AlarmManager.
To reproduce the bug follow these steps:
Start the app
start the service as a foreground service (use startForeground for that) from within the app
Swipe the app from "Recent Apps" list
Send a broadcast that is handled by the service
The service is killed !
Using adb shell dumpsys >C:\dumpsys.txt you can monitor the state of the service between the different steps. (look for Process LRU list in the dumpsys output)
on steps 2 and 3 you will see something like this:
Proc # 2: prcp F/S/IF trm: 0 11073:<your process name>/u0a102 (fg-service)
Specifically, notice the F/S/IF and the (fg-service) that indicate the service is running as a foreground service (more details on how to analyze the dumpsys at this link: https://stackoverflow.com/a/14293528/624109).
After step 4 you will not see your service in the Process LRU list.
Instead, you can look at the device logcat and you will see the following:
I/ActivityManager(449): Killing 11073:<your process name>/u0a102 (adj 0): remove task
What seems to be causing that behavior is the fact that the received broadcast takes the service out of its foreground state and then killed.
To avoid that, you can use this simple solution when creating your PendingIntent for the AlarmManager (Source: https://code.google.com/p/android/issues/detail?id=53313#c7)
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("YOUR_ACTION_NAME");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, 0);
Pay attention to the following steps:
Call addFlags on the intent and use FLAG_RECEIVER_FOREGROUND
Use a non-zero request code in PendingIntent.getBroadcast
If you leave any of those steps out it will not work.
Note that the FLAG_RECEIVER_FOREGROUND was added on API 16 (Jelly Bean) so it makes sense that this is when the bug first appeared...
Most likely that KitKat is just more aggressive when it comes to killing processes and this is why it was emphasized with KitKat, but looks like this was already relevant on Jelly Bean.
Note 2: Notice the details in the question about the service configuration - running in a separate process, as a foreground service, with endWithTask set to false in the manifest.
Note 3: The same thing happens when the app receives the android.appwidget.action.APPWIDGET_CONFIGURE message and shows a configuration activity for a new widget (Replace step 4 above with creating a new widget). I found that only happens when the widget provider (the receiver that handles android.appwidget.action.APPWIDGET_UPDATE) is set to run on a different process than the activity process. After changing that so both the configuration activity and the widget provider are on the same process, this no longer happens.

i found this simple trick to solve this problem without using AlarmManager.
create a broadcast receiver that listens broadcast everytime onDestroy() method in service is called:
public class RestartService extends BroadcastReceiver {
private static final String TAG = "RestartService";
public RestartService() {
}
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context, YourService.class));
}
}
add customized broadcast intent to your manifest
<receiver
android:name=".RestartService"
android:enabled="true" >
<intent-filter>
<action android:name="restartApps" />
</intent-filter>
</receiver>
then, send broadcast from onDestroy(), probably like this:
#Override
public void onDestroy() {
Intent intent = new Intent("restartApps");
sendBroadcast(intent);
super.onDestroy();
stopThread();
}
call onDestroy() from onTaskRemoved(Intent intent)
this trick will restart your service everytime user close service from both task manager and force close from settings, i hope this will help you too

Related

Android Service running on separate Process gets killed when I swipe out my App (running in other process)

I have an Android Service (implementation of Servcie interface) which is running on a separate process compared to my real app. Unfortunately when I leave my real App (in which I clicked the Button to start my Service) and swipe it out from Task Manager, my Service gets killed as well.
I know there are a lot of questions like this here, but somehow none are targeting the Problem in my concrete constellation or they are vaguely answered.
So in my manifest I have something like:
<application ...>
<activity .../>
<service Android:name="MyService"
Android:label="MyLabel"
Android:export="false"
Android:process=":MyRemoteProcessName" />
</application>
I first have played around with an IntentService, but also switched to an own implementation of the Service Interface (eliminating the IntentService to be the point of failure) which looks something like:
public class MyService extends Service {
private ScheduledExecutorService scheduledWorker = Executors.newSingleThreadScheduledExecutor();
#Override
public void onStart() {
// Init components
startForeground(this, MyNotification);
}
#Override
public int onStartCommand(Intent i, int startId) {
// Execute Work on Threadpool here
scheduledWorker.execute(new ScheduledStopRequest(this, startId), 5, TimeUnit.Minutes);
return START_REDILIVER_INTENT;
}
// Overwritten onDestroy-Method
#Override
public void onLowMemory() {
Log.e(LOG_TAG, "On Low Memory called!");
}
#Override
public IBind onBind() {
// Dont't want to let anyone bind here
return null;
}
// Simply tries to stop the service after e.g. 5 Minutes after a call
private static class MyRunnable implements Runnable {
// Constructor with params used in run method..
#Override
public void run() {
mReferenceToMyService.stopSelfResult(startId);
}
}
}
I'm starting my Service in an onClick-Listener on a special button, with an explicit Intent, which kinda looks like the following:
#Override
public void onClick(View v) {
Intent i = new Intent(this, MyService.class);
startService(i);
}
My Intention is to keep the Service running when the user leaves the app, so that the Service can finish downloading and storing some important data. When the user comes back to my app again, he can view the data (That's why I'm executing it in a separate process). So is this possible?
My assumption right now is, that Android somehow notices my Service is just being used by my App (due to missing IntentFilters in Manifest or explicit call rather than by filter?!) and thus kills it immediately when my App is closed (even when running as ForegroundService as you can see above).
Does it seem possible to you and might some changes in the call of the service fix this problem or am I getting the concept of a service wrong?
(One last note: onLowMemory-Method doesn't get called -> No log entries.)
So, according to your hints (and so new keywords for me to look for) and after some additional research by myself, I think I have solved my problem. During my research I have found an very interisting blog post on this topic, maybe also for you, which is why I would like to share it with you: http://workshop.alea.net/post/2016/06/android-service-kill/ .
After verifying and going through the steps in this article everything seems to work fine (so startForeground seems to solve the problem). I want to point out here, that I have only tested it, with my service instance still running in separate process, so manifest entries as is above.
The actual thing which really confused me at the beginning was my android studio debug session being killed everytime, just after swiping out my app from recent apps (menu). This made me think my service being killed by the system as well. But according to the article (I have added some logs to the callback methods provided) when
Opening my app
starting service
swiping out app
starting app again and finally
calling service again,
I only received callbacks to the methods as if my service would still be running. Having an explicit look at DDMS (tool) also prooved my 2nd process, and thus my service, being still alive. Having verified this, I then cleared all my app data and repeated the steps above (excluding step no. 5). Having had a look in the database afterwards, prooved the data having been downloaded by the service.
For the curious of you:
The process of swiping out my app from recent apps (and thus having the onTaskRemoved callback method being called) lead to another problem. It somehow increases the startId parameter of onStartCommand by 1 so that my DelayedStopRequest malfunctiones and doesn't stop my service anymore.
This means: Repeating above steps 1 - 3 makes me receive startId = 1 in onStartCommand. By calling stopSelfResult(1) later on (which was the latest startId) it returnes false and the service keeps running. Continuing to follow step 4 + 5 then, makes onStartCommand being called with startId = 3 (but should actually be 2! which is skipped somehow). Calling stopSelfResult(3) with parameter 3 later on is then going to stop the service again (also visible in screenshots).
I hope my answer is correct so far (, understandable) and also helpful for you. Thank you for all of your answers which provided beneficial input and also pointed me to the solution. The android version I have been working with is:
4.1.2 - Jelly Bean | API Level : 16
I also added screenshots of the log entries from DDMS (imgur is rejecting my uploads so you'll temporarily have a link to my dropbox):
screenshots from logs from DDMS
Unfortunately running service in a separate process does not help you. I think there is no way you can prevent your service from being closed if user removes its task. You can however restart your service overriding onTaskRemoved. See this answer.
If you want to run this service class indefinitely after closing the app also.. you should use Alaram Manager class ..
public void scheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(this, LocationListnerServiec.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, MyAlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
60000, pIntent);
}
Use this method for keep checking the service class is on or off.. By using this method Your service class will keep working after destroying of you application.

BroadcastReceiver dies with app

If i let the phone sit for a long time like 15 minutes i lose my receiver but i thought it was to persist like a service after being killed for memory.
Manifest:
<receiver
android:name=".WearableReceiver"
android:enabled="false">
<intent-filter>
<action android:name="com.example.johnbravado.MESSAGE_PROCESSED"/>
</intent-filter>
</receiver>
In Activity to start receiver
ComponentName component = new ComponentName(CounterActivity.this, WearableReceiver.class);
getPackageManager()
.setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
The receiver
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
//MyConstants.getInstance().showToast("Message Rcvd");
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"com.example.johnbravado");
wakeLock.acquire();
// Do Work
MyConstants.getInstance().msgReqAction(intent.getIntExtra(MyConstants.BROADCAST_DATA_REQ, 0));
wakeLock.release();
}
The broadcast sender
String BROADCAST_ACTION_RESP = "com.example.johnbravado.MESSAGE_PROCESSED"
#Override
public void onMessageReceived(final MessageEvent messageEvent) {
nodeId = messageEvent.getSourceNodeId();
String incomingPath = messageEvent.getPath();
int incomingReq = Integer.parseInt(new String(messageEvent.getData()));
if(incomingPath.equalsIgnoreCase(MyConstants.MSG_COUNTER_REQ_PATH)) {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(BROADCAST_ACTION_RESP);
broadcastIntent.putExtra(MyConstants.BROADCAST_DATA_REQ, incomingReq);
sendBroadcast(broadcastIntent);
}else if(incomingPath.equalsIgnoreCase(MyConstants.MSG_DEFAULT_PATH)){
}
}
only way I get this to persist for long periods of time is to invoke a service
wearableReceiverIntent = new Intent(this, WearableReceiverService.class);
if(!WearableReceiverService.isRunning())
startService(wearableReceiverIntent);
the service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
IntentFilter filter = new IntentFilter(MyConstants.BROADCAST_ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new WearableReceiver();
registerReceiver(receiver, filter);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_notif_bible)
.setContentText("Preaching").build();
startForeground(MyConstants.NOTIF_COUNTING_SERVICE, notification);
isRunning = true;
return START_STICKY;
}
If I run the service it persists for long periods of time but it drains the battery unnecessarily considering I interact only once every 10 minutes. I was under impression Broadcast receiver would work like service except for short bursts of work. invoke the service if you need to do long actions.
A BroadcastReceiver handles an intent and then stops again. This handling of an intent should be fast. If you want to do a lot of stuff, you should start an Service from the BroadcastReceiver and handle it from there.
A BroadcastReceiver object is only valid for the duration of the call
to onReceive(Context, Intent). Once your code returns from this
function, the system considers the object to be finished and no longer
active.
A BroadcastReceiver is started using the sendBroadcast intent.
So remove android:enabled="false" and use sendBroadcast, which will startup the Receiver by Android.
http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html
Greenify was killing my app when the screen went off. I was battling something I had no hope of defending against with code. After I explicitly told Greenify to not kill my app, I never told it to kill my app to begin with, everything worked as intended.
I had the same problem due on my Asus ZenPad due to the Asus Mobile Manager app, specifically the "Auto start manager" was blocking the intent to my app.
Deactivating the app (uninstall is not possible) worth nothing, the solution has been to leave the app installed but whitelist my developing app so it can receive broadcast like PACKAGE_REPLACE. (Pay attention that the switches are confusing, you actually have to touch on "blocked" so it turns on into "allowed" to enable it.
I think another option is to update or change the ROM (choosing one without all that bloatware).
If your BroadcastReceiver is setup in your manifest, there is no need to try and adjust the PackageManager component information for your package. As long as you remove the enabled="false" part.
Your BroadcastReceiver should be very short with what it does: typically update some internal data or start another component which can do the heavy lifting of your app's operation. You can use it to trigger a Service to do this type of thing in the background. But, note that "background" in this case means without user-interaction. It does not mean a background context of execution, such as a secondary thread. It is up to you do manage the thread(s) in your Service. Your BroadcastReceiver and Service callback entry points (onReceive() and onStartIntent()) run in the context of the main thread of your app.
Power management definitely plays a roll in all of this. Is your broadcast Intent actually being sent and done in a way which will wake the device? If it does wake the device and send the Intent, the device will only stay awake long enough for the BroadcastReceiver to run its onReceive(); after that returns there are no guarantees. The device will aggressively sleep, which is why wakelocks are a thing. However, use of wakelocks can cause excessive battery drain, unless used properly. If you are running on Marshmallow or newer, the Doze functionality can also wreck havoc on your plans. Wakelocks are ignored when in Doze mode and won't be considered until the user brings the device out of doze.
I had the same issue and it was resolved by granting auto launch permission for the app.
Go to
Settings->Permissions->Manage Auto Launch
and allow auto launch for your app.

Foreground service gets killed on performing internet related operations

UPDATE: Previously I couldn't find a well defined pattern as to when my foreground service was being killed. After more debugging with the devices (doesn't happen on all) on which this was happening I found.
1.) A lot of times when I open chrome to load a website the foreground service gets killed. Sometimes even when I am using whatsapp this happens.
2.) There are no exceptions and the stacktrace doesn't show anything useful.
Original Question below:
There are many such questions on StackOverflow but the answers so far that I have read mostly say that it is upto Android and we don't have 100% guarantee that a foreground service will not be killed. Some answers suggest START_STICKY but that is not much helpful in my case.
In my case I have a music player app which has a foreground service. This service gets killed on certain devices, mostly some versions of Xiomi (Android version was 5.1.1). Now I understand that android might be short on memory and so my foreground service is being killed, but then why do other music player apps never go through such termination. What is it that they are doing right that I am not?
I made my service foreground service by using startForeground. Also I return START_STICKY in onStartCommand although that doesn't help because the service is restarted after a period of 4-5 sec if killed. To bind my service with my activity I use
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT );
So what exactly can I improve/change in my app to prevent this from happening, if other apps are working right there must be something that is wrong in my case. Can someone please help. Thanks in advance !!
Edit:
This is how I call startForeground()
public void sendNotification() {
Intent notIntent = new Intent(this, MainActivity.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bitmap = null;
if (!notificationShowing || !forwarded) {
Log.i(TAG, "present");
String title = CommonUtils.getSongFromID(songIndex, this);
bigView.setTextViewText(R.id.title, title);
bigView.setImageViewBitmap(R.id.img, bitmap);
smallView.setTextViewText(R.id.title1, title);
smallView.setImageViewBitmap(R.id.img1, bitmap);
if (pauseButton == 1) {
bigView.setImageViewResource(R.id.pause, R.drawable.pause_noti);
smallView.setImageViewResource(R.id.pause1, R.drawable.pause_noti);
} else {
bigView.setImageViewResource(R.id.pause, R.drawable.play_noti);
smallView.setImageViewResource(R.id.pause1, R.drawable.play_noti);
}
musicNotification = builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.logo1)
.setTicker(songTitle)
.setOngoing(true)
.setContentTitle("Playing")
.setStyle(new Notification.BigTextStyle().bigText("Song App"))
.setContentText(songTitle)
.setPriority(Notification.PRIORITY_MAX)
.build();
musicNotification.contentView = smallView;
musicNotification.bigContentView = bigView;
musicNotification.contentIntent = pendInt;
Intent switchIntent = new Intent("pause");
switchIntent.putExtra("button", "pause");
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 100, switchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.pause, pendingSwitchIntent);
smallView.setOnClickPendingIntent(R.id.pause1, pendingSwitchIntent);
Intent switchIntent1 = new Intent("forward");
switchIntent1.putExtra("button", "forward");
PendingIntent pendingSwitchIntent2 = PendingIntent.getBroadcast(this, 100, switchIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.forward, pendingSwitchIntent2);
smallView.setOnClickPendingIntent(R.id.forward1, pendingSwitchIntent2);
Intent switchIntent2 = new Intent("previous");
switchIntent2.putExtra("button", "previous");
PendingIntent pendingSwitchIntent3 = PendingIntent.getBroadcast(this, 100, switchIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.previous, pendingSwitchIntent3);
smallView.setOnClickPendingIntent(R.id.previous1, pendingSwitchIntent3);
Intent switchIntent3 = new Intent("end");
switchIntent3.putExtra("button", "end");
PendingIntent pendingSwitchIntent4 = PendingIntent.getBroadcast(this, 100, switchIntent3, PendingIntent.FLAG_UPDATE_CURRENT);
bigView.setOnClickPendingIntent(R.id.end, pendingSwitchIntent4);
smallView.setOnClickPendingIntent(R.id.end1, pendingSwitchIntent4);
startForeground(NOTIFY_ID, musicNotification);
notificationShowing = true;
}
forwarded = false;
}
This happened in Xiomi phone due to below reason.
Solution for MIUI 7.0 => Security => Autostart => select Apps that you want to run in background => Reboot
After reboot your device should able to run your application services in background like other android devices do.
MIUI 4.0 settings
MIUI AutoStart Detailed Description
And if you looking for other phone then check here is service structure.It automatically restart but when you restart phone call BootReceiver.
public class AppService extends Service {
private class LocalBinder extends Binder {
public AppService getServerInstance() {
return AppService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// If we get killed, after returning from here, restart
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
}
}
Thanks hope this will help you.
This service gets killed on certain devices, mostly some versions of
Xiomi (Android version was 5.1.1)
Not sure about this, but as per my understanding this might be because of
Bug in os customization from the vendor.
Bugs in Android with respect to prioritizing foreground services, that are triggered by various combinations of service binding flags(i.e. BIND_AUTO_CREATE, BIND_IMPORTANT etc).Read this answer by Robin Davies.
I don't know whether you use startService() or not. But if you don't then as per this documentation:
You can create a service that is both started and bound. That is, the
service can be started by calling startService(), which allows the
service to run indefinitely, and also allow a client to bind to the
service by calling bindService().(This is called Binding to a Started Service)
If you do allow your service to be started and bound, then when the
service has been started, the system does not destroy the service when
all clients unbind. Instead, you must explicitly stop the service, by
calling stopSelf() or stopService().
Although you should usually implement either onBind() or
onStartCommand(), it's sometimes necessary to implement both. For
example, a music player might find it useful to allow its service to
run indefinitely and also provide binding. This way, an activity can
start the service to play some music and the music continues to play
even if the user leaves the application. Then, when the user returns
to the application, the activity can bind to the service to regain
control of playback.
Be sure to read the section about Managing the Lifecycle of a Bound Service, for more information about the service lifecycle when adding binding to a started service.
onStartCommand will be called in case of started service so START_STICKY will work in case of startService() only.
Update on process logs
Proc # 5: prcp F/S/IF trm: 0 22407:com.wave.music.player/u0a2
(fg-service)
In your process log your player service running in foreground with adj setting prcp (visible foreground service) which means it's virtually indestructible. Still your service destroyed by OS than there might be very low memory available to run newly launch app. As per this documentation,
There will only ever be a few foreground processes in the system, and these
will only be killed as a last resort if memory is so low that not even
these processes can continue to run. Generally, at this point, the
device has reached a memory paging state, so this action is required
in order to keep the user interface responsive.
So I think you are doing nothing wrong. I just want to suggest you to read this official Android developer documentation and try to run your service in separate process(Documentation suggests this approach for music player app). Be careful to implement this as it can easily increase—rather than decrease—your RAM footprint if done incorrectly.

Only want Alarm to die when removed from Recent Apps or user forced killed

I have an application that does something in a service triggered by an alarm every 10 minutes while the app is in the background. I want the Alarm to keep going off even if the OS kills the app (So its dead and have to relaunch) and only kill it if the user actually removes the app from recent apps or force kills it from settings (or is logged off but that already works). I have tried many different approaches, latest I tried this http://www.dotkam.com/2011/01/10/android-prefer-alarms-and-intent-receivers-to-services/ without any luck. My Alarm looks like this.
if(ActivityLifecycleHandler.isApplicationInForeground()) {
return; // If App is in foreground do not start alarm!
}
String alarm = Context.ALARM_SERVICE;
AlarmManager am = ( AlarmManager ) context.getSystemService( alarm );
Intent intent = new Intent(locationBroadcastAction);
PendingIntent pi = PendingIntent.getBroadcast( context.getApplicationContext(), 0, intent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
// Set trigger time to 0, because want to fire off the first one instantly
am.setRepeating( type, 0, ONE_MINUTE, pi );
And the BroadcastReceiver:
public class LocationBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent ) {
Intent myIntent = new Intent( context, LocationService.class );
context.startService( myIntent );
}
}
Any idea of what I am doing wrong? Everything works fine until the OS kills the app.
The alarm should goes off if the app was killed, even if if was removed from the recent app (but not if it was force-stopped).
It is actually the whole point of using the AlarmManager :
Note: The Alarm Manager is intended for cases where you want to have
your application code run at a specific time, even if your application
is not currently running. For normal timing operations (ticks,
timeouts, etc) it is easier and much more efficient to use Handler.
You can see if the alarm is still there with :
adb shell dumpsys alarm
What is probably happening is that the device is woken up to receive the alarm, but fall asleep again as soon as the receiver finishes, before the service can start.
The receiver should take a wake lock (to be released by the service). The support library provides a WakefulBroadcastReceiver which does exactly that :
Helper for the common pattern of implementing a BroadcastReceiver that
receives a device wakeup event and then passes the work off to a
Service, while ensuring that the device does not go back to sleep
during the transition.

How to automatically restart a service even if user force close it?

I want a service to run all the time in my application. So I want to restart it even if it is force closed by user. There is definitely a way to do it as apps like facebook are doing it. It's not done using push notification, facebook restarts its service even if internet is off.
First of all, it is really very bad pattern to run service forcefully against the user's willingness.
Anyways, you can restart it by using a BroadcastReceiver which handles the broadcast sent from onDestroy() of your service.
StickyService.java
public class StickyService extends Service
{
private static final String TAG = "StickyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("YouWillNeverKillMe"));
}
}
RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
private static final String TAG = "RestartServiceReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG, "onReceive");
context.startService(new Intent(context.getApplicationContext(), StickyService.class));
}
}
Declare the components in manifest file:
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Start the StickyService in a Component (i.e. Application, Activity, Fragment):
startService(new Intent(this, StickyService.class));
OR
sendBroadcast(new Intent("YouWillNeverKillMe"));
You have to create a sticky service with overriding onTaskRemoved method, where you can set an alarm service to trigger your code again.
public class BackgroundService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
//create an intent that you want to start again.
Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
super.onTaskRemoved(rootIntent);
}
}
Also in some devices like Xiaomi, Huwaei the app gets force closed once it's removed from recent apps. This is because the manufacturers have task manager features which improve ram/battery performance.
You can check this link for more information: https://stackoverflow.com/a/41360159/2798289
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.
FLAG_INCLUDE_STOPPED_PACKAGES — Include intent filters of stopped applications in the
list of potential targets to resolve against.
FLAG_EXCLUDE_STOPPED_PACKAGES — Exclude intent filters of stopped applications from the
list of potential targets.
When neither or both of these flags is defined in an intent, the default behavior is to
include filters of stopped applications in the list of potential targets.
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 stopped 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 FLAG_INCLUDE_STOPPED_PACKAGES intent flag and send it from another app
If I understand correctly, then actually this is not possible, Android feature to force close application was designed to allow user to get rid of unwanted applications, so it disallows any activities from it until user again starts any of its Activity.
Restart the service even if app is force-stopped and Keep running service in background even after closing the app How?
Whenever a service is killed, its onDestroy method is always called.
Its better to use a BroadcastReceiver to start your service when it is killed.
Here is a sample code illustrating its implementation:-
#Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("StartkilledService");
sendBroadcast(in);
Log.d("debug", "Service Killed");
}
Then register a receiver in AndroidManifest.xml:-
<receiver android:name=".app.ServiceDestroyReceiver" >
<intent-filter>
<action android:name="StartKilledService" >
</action>
</intent-filter>
</receiver>
Finally,create a BroadcastReceiver,and start your service in the onReceive method:-
#Override
public void onReceive(Context context, Intent intent) {
Log.d("debug", "ServeiceDestroy onReceive...");
Log.d("debug", "action:" + intent.getAction());
Log.d("debug", "Starting Service");
ServiceManager.startService();
}
Hope this helps.
on the service's startCommand method return START_STICKY. generally it tell the OS to start the service when it is killed.
If the situation allows to use 'root' it's usually possible to implement Humpty-Dumpty paradigm.
Your application (1st) installs another application (2nd, taking APK from assets) and runs the service of the 2nd app.
2nd app's service bind to the 1st app service and rebinds when disconnected. The 1st app does the same.
Sure it will not help when all apps are killed by some Free RAM or similar application but when Android kills either of those two, the other one will restart its counterpart.
The only real solution for keeping services alive ist to call Service.startForeground(...) with a provided Notification. This will be the only valid solution, every other one will be very dependent on how Google will change the behaviour of it's system. With every API update, Google could prevent every other hack.
This also keeps the user aware, that your app is performing some background task which will keep the app alive and the user has to stop this. If you provide the user the ability to stop it is part of your application, though.
See the Documentation:
void startForeground (int id, Notification notification)
Make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state. By default services are background, meaning that if the system needs to kill them to reclaim more memory (such as to display a large page in a web browser), they can be killed without too much harm. You can set this flag if killing your service would be disruptive to the user, such as if your service is performing background music playback, so the user would notice if their music stopped playing.
There is a very hacky solution to keep service running even you force stop it. I do not recommend that because it is against user willingness. You can define a broadcast receiver to receive intent with action X. onStartCommand handler of your service, broadcast X (if the service is not started yet). on broadcast receiver upon receipt of X, first start the service, then, sleep for some minutes, and finally re-broadcast X.
I think the only foolproof solution here is to have 2 services in separate processes (android:process="somecustomprocessname" in manifest, in the service entry) that both listen to broadcasts and restart each other, because currently the UI doesn't let users kill multiple processes in one action. You can then set up a pinger thread in each service that checks if the other service is running every 100 milliseconds or so, and if not, attempts to restart it. But this is starting to look more and more like malware...

Categories

Resources