traccar / traccar-client-android

Traccar Client for Android
https://www.traccar.org/client
Apache License 2.0
666 stars 738 forks source link

Stopping Apps On Android 4.4.2 Can Silently Kill Related Background Services #142

Open shuricksumy opened 9 years ago

shuricksumy commented 9 years ago

Hi, I face with the same issue on my phone with android 4.4.2. I've found out that it's the android issue. The details: link Will be good to implement the restarting of service using the AlarmManger Thanks.

shuricksumy commented 9 years ago

Hi. I have never coded on android. But I try to improve this one as in example. Now service is restarted automatically if it was killed. I checked it on my device with android 4.4.2.

diff --git a/traccar-client/src/main/java/org/traccar/client/AutostartReceiver.java b/traccar-client/src/main/java/org/traccar/client/AutostartReceiver.java
index e9c0011..a15fde9 100644
--- a/traccar-client/src/main/java/org/traccar/client/AutostartReceiver.java
+++ b/traccar-client/src/main/java/org/traccar/client/AutostartReceiver.java
@@ -20,6 +20,9 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
+import android.os.PowerManager;
+import android.app.AlarmManager;
+import android.app.PendingIntent;

 public class AutostartReceiver extends BroadcastReceiver {

@@ -27,10 +30,33 @@ public class AutostartReceiver extends BroadcastReceiver {

     @Override
     public void onReceive(Context context, Intent intent) {
+
+       PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+       PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
+       wl.acquire();
+
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        if (sharedPreferences.getBoolean(TraccarActivity.KEY_STATUS, false)) {
            context.startService(new Intent(context, TraccarService.class));
        }
+
+       wl.release();
     }

+   public void SetAlarm(Context context)
+   {
+       AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+       Intent i = new Intent(context, AutostartReceiver.class);
+       PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
+       am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 1, pi); // Millisec * Second * Minute
+   }
+
+   public void CancelAlarm(Context context)
+   {
+       Intent intent = new Intent(context, AutostartReceiver.class);
+       PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
+       AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+       alarmManager.cancel(sender);
+   }
 }
+
diff --git a/traccar-client/src/main/java/org/traccar/client/TraccarService.java b/traccar-client/src/main/java/org/traccar/client/TraccarService.java
index afb007c..df36b10 100644
--- a/traccar-client/src/main/java/org/traccar/client/TraccarService.java
+++ b/traccar-client/src/main/java/org/traccar/client/TraccarService.java
@@ -51,6 +51,8 @@ public class TraccarService extends Service {

     private WakeLock wakeLock;

+    AutostartReceiver alarm = new AutostartReceiver();
+
     @Override
     public void onCreate() {
         StatusActivity.addMessage(getString(R.string.status_service_create));
@@ -82,10 +84,24 @@ public class TraccarService extends Service {
     }

     @Override
+    public void onStart(Intent intent, int startId)
+    {
+        alarm.SetAlarm(this);
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId)
+    {
+        alarm.SetAlarm(this);
+        return START_STICKY;
+    }
+
+    @Override
     public IBinder onBind(Intent intent) {
         return null;
     }

+
     @Override
     public void onDestroy() {
         StatusActivity.addMessage(getString(R.string.status_service_destroy));
jaimzj commented 9 years ago

could you please copy paste it, without the + signs, just the code?

shuricksumy commented 9 years ago

jamejo could you please copy paste it, without the + signs, just the code?

It is a diff between my changes and master branch. Copy these changes in file.patch. Clone master branch. And apply this patch: git apply file.patch

tananaev commented 9 years ago

I have added START_STICKY to the service (https://github.com/tananaev/traccar-client-android/commit/fc83e7525a67fb650d8b5ed426229836f46d5ddd). I think it should fix the problem without the need for Alarms.

@shuricksumy, what do you think?

shuricksumy commented 9 years ago

Hi. I am not sure that START_STICKY will help to restart service on android 4.4.2. At first I tried to use just START_STICKY, but service was not restarted on my device. I am ready to check new code. But also I want to add that using of Alarms very useful, I use modified traccar-client-android for several days and service is always running. I used task killer which are very popular now. I over used memory on my device using browsers and other huge apps. But service is restarted every time and it worked well.

redge76 commented 9 years ago

Hi, START_STICKY should be the way to solve the issue. But as explained in the link in the first post of this issue, there seems to be a bug and the suggested workaround is to use AlarmManager. But even if the START_STICKY worked, don't you think that AlarmManager should be used to schedule the position polling ? You are currently using a wakelock an this quite bad for the battery drain. As already suggested by mhdyousif here and here , I think AlarmManager is a better approach. Also as you suggested you need to move to a HTTP protocol so that an always open TCP connection no needed. In my fork, as suggested by Armagetron, I don't need a wakelock because the TCP connection will wakeup the device. /(my theory) Redge. See also

tananaev commented 9 years ago

I think using alarm manager for position updates is a really good idea. Furthermore, I want to rely on standard location update mechanism plus use AlarmManager functionality for mixed provider. I want to implement it over the weekend.

As for using alarm manager to keep service awake, I'm not so sure. I think STICKY service should be enough. Also, in future looks like we would have to use foreground service (see app standby mode in Android M). Any thoughts?

I have one question about your patch. Why do we need wake lock in AutostartReceiver?

As for HTTP protocol, it's already implemented. I have made a lot of changes in the code over the last few days.

shuricksumy commented 9 years ago

I use wake lock in AutostartReceiver because it was in the example of using AlarmManager. I am not good in development for android, so I tried do it using this example. As for using only STICKY, of course it will be enough. But some devices with issue on android 4.4.2 will have problem with restarting service.(START_STICKY does not work on Android KitKat) Thanks for your work. I will try fix this problem for my device using AlarmManager.

tananaev commented 9 years ago

I have implemented foreground service option. Please try new version of Traccar Client (3.3) and see if it solves the problem with Android KitKat.

shuricksumy commented 9 years ago

I installed latest version of traccar-client-android on my device (foreground service option was enabled).

  1. Now service is not destroyed if I clean latest apps from memory using standard method of android interface.
  2. Now service is not destroyed if there is not free memory on your device and android try get some free memory by killing old processes. Once I found that this process was killed. But I tried to reproduce this again and couldn't do it.
  3. Service is not restarted if I destroy it using taskkiller. So we should add traccar-client-android as exception for popular ramcleaner and speedup apps.

Anton, thanks for your work.

tananaev commented 9 years ago

Thanks for feedback. I guess we leave it as a foreground service. In future I will probably force foreground option (at least on Android M).