Service crashing and restarting
Asked Answered
A

3

4

There are several questions about it but I always read the same thing: "the service will be killed if the system need resources" or "you can't build an service that runs forever because the more it runs in background, more susceptible it is to the system kills it" and etc.

The problem I'm facing is: My service runs fine and as it is expected, if I run my app then exit it my service is still running, but when I kill my app (by going to the "recent apps" and swype it away) the service stops. In this moment, if I go to the Settings >> aplications >> running I'll see that the service is restarting. After a while, it goes back and my Service run with no problem.

I google it and I find some things I could do but lets see my code first:

I start my service by this way (after a button click):

Intent intent = new Intent (MainActivity.this, MyService.class);
startService(intent);

I also have 3 Integers I put in extra, so I have something like this:

final Integer i, i2, i3;
i = 5; //for example
i2 = 10; //for example
i3 = 15; //for example
final Intent intent = new Intent (MainActivity.this, MyService.class);
intent.putExtra("INTEGER1", i);
intent.putExtra("INTEGER2", i2);
intent.putExtra("INTEGER3", i3);
startService(intent);

In MyService I have the folloywing:

public class MyService extends Service
{

  AlarmManager am;
  BroadcastReceiver br;
  PendingIntent pi;
  Integer i, i2, i3;

  @Override
  public void onCreate()
  {
    super.onCreate();
    am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros?

    br = new BroadcastReceiver ()
    {
      public void onReceive (Context context, Intent i) {
        new thread(new Runnable()
        {
          public void run()
          {
            //do something
          }
        }).start();
      }
    };
  }

  @Override
  public void onStartCommand(Intent intent, int flags, int startId)
  {
    super.onStartCommand(intent, flags, startId);
    try
    {
      i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here
      i2 = intent.getIntExtra("INTENT2", 0)
      i3 = intent.getIntExtra("INTENT3", 0);
    }
    catch(NullPointerException e) {}

    this.registerReceiver(br, new IntentFilter("anyany"));

    new thread(new Runnable()
    {
    public void run()
      {
      am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock. elapsedRealtime() + i*1000, i2*1000, pi);
      }
    }).start();
  return START_REDELIVER_INTENT; //so I can get my Extra even with my Activity closed
}

My onDestroy:

@Override
public void onDestroy()
{
  unregisterReceiver(br);
  super.onDestroy();
}

I also have onBind() method (without @Override), but it returns null. I google a lot and I tried to run the service in foreground, so I did this (inside de onStartCommand):

Notification n = new Notification(R.drawable.ic_laucher), getText(R.string.app_name), System.currentTimeMillis());
PendingIntent npi = PendingIntent.getActivity(this, MainActivity.class);
n.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), npi);
startForeground(3563, n);

My notification appears and when I click on it my app runs, but the problem with my service wasn't fixed (I believe it still not run on foreground). The notification is restarted too.

I also deleted the Try catch and I define a value for the integers (so I didn't use the getIntExtra() method), but nothing changed

After several tests I tried to see the logs, when I kill my App I have the following message: Scheduling restart of crashed service.

So, for some reason my service crash when my MainActivity dies, why? The intention here is not to transform the service in a god that can not be killed (I don't think it is impossible at all, the WhatsApp are running for 105 hours !) but prevent my Service to not being crashed after my App dies.

I don't know if this'll help but this is what I add on my Manifest.xml

<Activity android:name = ".MyService"/>
<service android:name ="Myservice" android:enabled="true" android: exported="false"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

Min API = 9, target API = 17. Size of the Service when running: about 3MB.

Hope I was clear and sorry for my English.

PS: the entire code are running as expected, so if you see any sintax error fell free to edit it.

EDIT

If I add android:isolatedProcess="true" in the <service> in AndroidManifest.xml I receive this error in logCat: java.lang.RuntimeException: Unable to create a service in com.mycompany.myapp.myservice: java.lang.SecurityException: Isolated process not allow ed to call getIntentSender

When I start my service using this, the MainActivity does not show any erros, only the service crashes.

Astra answered 21/7, 2013 at 4:4 Comment(0)
A
11

I finally found the solution ! I removed the AlarmManager from the Service and the service does not cashed anymore, but I have to use it

The problem is the service crash after the user swype away the app from Recent App, so what I did was prevent the app to appear in that window. Add the following to your AndroidManifest.xml as a child of <activity>

android:excludeFromRecents="true"

Now when the user exit from your app it wil not appear in the recent apps window, what means the system kills the Activity right after you exit it, so it'll not waste any resources.

PS: don't forget to set the service to run in a separate process, add the following to your AndroidManifest.xml, as a child of <service>

android:process=":remote"

EDIT - REAL SOLUTION FOUND

After a lot of research and study (months of study) I took a deep look at android APIs and here is what a found, this is na expected behaviour that occours only at API 16+, a change at android arquiteture changed the way that PendingIntents are broadcasted by the system, so Google added the flag FLAG_RECEIVER_FOREGROUND, you must pass this flag to the intent you are using as a parameter on the PendingIntent.getBroadcast(), here is na example:

if(Build.VERSION.SDK_INT >= 16)     //The flag we used here was only added at API 16    
    myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    //use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;



PendingIntent pi = PendingIntent.getBroadcast(context, 1, myIntent, 0); // the requestCode must be different from 0, in this case I used 1;

Android versions older than API 16 will work as expected, the service won't crash if you swype away the app from Recent Apps page.

Astra answered 13/8, 2013 at 2:34 Comment(4)
My app crashes if i swipe it left at the time service is running in background. Any help on this?Presuppose
This works for me in the case you're sending the broadcast. But, for example with Google Cloud Messaging's Broadcast, I'm not able to add the flag and the Service still crashing...Curtsey
@Curtsey - I am stuck in the same problem. how did you solve it for GCM?Illsorted
App is not shown in the recent app list, but still the service crash if user clears all the recent app list.Gerigerianna
G
3

As the documentation says, a Service runs in the main thread of its callee, that usually is the UI Thread. So what is happening is that when you kill your application, you kill your application process and thus the service is killed too.

You can workaround this behavior by creating your Service in a different process by using android:process in your <service> tag in the Manifest.xml file.

Usually, though, you start a Service in its own process if the Service needs to be independent from the callee and if it may be used by different application. If your Service is for your own application use only, then stick with the default behavior and simply don't kill you application.

EDIT 1:

The documentation for android:isolatedProcess says:

If set to true, this service will run under a special process that is isolated from the rest of the system and has no permissions of its own. The only communication with it is through the Service API (binding and starting).

Glycogenesis answered 21/7, 2013 at 4:24 Comment(10)
I added this: android:process=":remote" but nothing changed.Astra
Then probably you are killing the whole DVM environment and not just a single process. Every application run on its own DVM, so you may need to implement your service in a whole different application that is, a whole new .apk package.Glycogenesis
So the service would be some kind of a "plugin" of my app? ? I'll search why the whole DVM is being killed and see if has something I can do to fix it.Astra
If your service needs to run independently from your application main thread then it has to be a standalone application.Glycogenesis
Ohh I tried this too: android:isolatedProcess= "true", then when the servive starts, it crashes but the MainActivity still run without any erros. After a while I receive another error saying the same thing (MyApp stopped), but the MainActivity still run after those 2 errors (when the service crashes, in any case, I always receive two erros). Is this change anything? I'll see the logs then I post in the question.Astra
I have edited my answer. Maybe (I didn't check) ALARM_SERVICE needs a permission and so you can't use it.Glycogenesis
I updated my question, the logCat is there. And no, the ALARM_SERVICE by it self does not need any permission, but the permission WAKE_LOCK is required if I use this type of AlarmManager: ELAPSED_REALTIME_WAKEUPAstra
Take a look here, there is the source of the error: android.googlesource.com/platform/frameworks/base/+/…. My guess is that registerReceiver or setRepeating is throwing the error...try commenting lines!Glycogenesis
Ok I'll check it but I was testing other apps, if I open the WhatsApp for example and then kill it the service will restart and turn back in few seconds, but the Notification does not disappear so my guess is the Notification runs in an isolated process and the service in another one, using the onBind() to communicate. Also they should not have any getExtra() or putExtra() because if you see my log you'll find: Isolated process not allowed to call getIntentSender, so I think the error is with those extras I'm trying to receive, I'll see how I can use the onBind() method to fix this problem.Astra
Thanks very much for your help, you gave me another start point to begin my search o/Astra
F
1

From another SO answer (Link), this is the expected behavior. But surely, someone here will have a workaround or a solution.

Your questions from code:

pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros?

The first zero you see is mentioned as a requesCode and decribed as not being used presently:

requestCode: Private request code for the sender (currently not used).

The second zero should actually be one of the flags given (here).

i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here

The getIntExtra(String, int) method of Intent doesn't need to have 0 as its second argument: it can be any integer. getIntExtra(String, int) returns an integer corresponding to the String key you provide. In the event that this key no long exists(or never did), getIntExtra(String, int) returns the integer we pass as the second argument. It is the default value when the key fails.

Funest answered 21/7, 2013 at 4:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.