AlarmManager alarm not working when the device is asleep in Android

I need to have a piece of code run every time period, even if the app is killed or the device sleeps.

I am using AlarmManager to achieve this and it kinda works, but when the device sleeps for about five minutes the Service is not being called anymore... Does anyone know what am i doing wrong ??

here is my code:

public class Profiler extends IntentService {

    public static final int ALARM_MANAGER_ID = 21436587;

    public Profiler() {
        super("Profiler");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        JodaTimeAndroid.init(getApplicationContext());
        System.out.println("Testing profiles");
        List<Profile> profiles = MainActivity.getStoredProfiles(getApplicationContext());

        if (profiles != null) {
            for (Profile profile : profiles) {
                if(profile.check()) {
                    profile.set(getApplicationContext());
                }
            }
        }

        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        Intent intent2 = new Intent(getApplicationContext(), Profiler.class);
        PendingIntent pIntent = PendingIntent.getService(getApplicationContext(), ALARM_MANAGER_ID, intent2, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, DateTime.now().plusSeconds(10).getMillis(), pIntent);
    }
}

And one more question. Is this method of calling service reliable ??

Here is the log

07-24 11:31:24.654 17689-19078/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:34.671 17689-20364/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:34.673 17689-20364/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:34.674 17689-20364/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:44.692 17689-21571/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:44.693 17689-21571/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:44.694 17689-21571/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:31:54.704 17689-22753/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:31:54.705 17689-22753/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:31:54.706 17689-22753/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:32:04.717 17689-24015/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:32:04.718 17689-24015/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:32:04.718 17689-24015/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}
07-24 11:35:29.032 17689-17475/cz.fjerabek.soundprofiler I/System.out: Testing profiles
07-24 11:35:29.040 17689-17475/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":11,"minute":15}
07-24 11:35:29.050 17689-17475/cz.fjerabek.soundprofiler I/System.out: {"type":"Time","hour":0,"minute":0}

                                                                       [ 07-24 11:35:29.056 17476:17476 I/         ]
                                                                       power log dlsym ok

the application was started at 11:31, and now its 11:40 as you can see the last execution of the code was at 11:35 and before that at 11:32 its 3 minutes then it seems like its getting called every 5 minutes.

I am starting the service with:

Intent bgServiceIntent = new Intent(getApplicationContext(), Profiler.class);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        if(checkNotificationPolicy(getApplicationContext())) {
            startService(bgServiceIntent);
        }
    } else {
        startService(bgServiceIntent);
    }

Device i am using: HUAWEI P9 lite (VNS-L21)

Upvotes: 4

Views: 772

Answers (1)

earthw0rmjim
earthw0rmjim

Reputation: 19417

The cause of the problem is most probably Doze.

From its docs regarding AlarmManager:

To help with scheduling alarms, Android 6.0 (API level 23) introduces two new AlarmManager methods: setAndAllowWhileIdle() and setExactAndAllowWhileIdle(). With these methods, you can set alarms that will fire even if the device is in Doze.

You should call the appropriate AlarmManager method based on the API level to make sure the alarm goes off even when the device is asleep:

if (Build.VERSION.SDK_INT >= 23) {
    alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
            alarmMillis, alarmIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
    alarmManager.setExact(AlarmManager.RTC_WAKEUP,
            alarmMillis, alarmIntent);
} else {
    alarmManager.set(AlarmManager.RTC_WAKEUP,
            alarmMillis, alarmIntent);
}

Take the following into account:

Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 9 minutes, per app.

As you said you're testing on a Huawei device.

Huawei (among other manufacturers) has implemented certain battery saver functions that can prevent alarms from going off. You have to add your app to the "protected" apps.

Check out the following questions: 1 & 2

It is not recommended to do this programmatically, a proper solution could be to warn your users at startup (with an AlertDialog for example) to manually make your app "protected" in the battery manager.

Upvotes: 5

Related Questions