Android exact Alarm is always 3 minutes off
Asked Answered
A

1

22

I have an app which uses the AlarmManager to regularly wake up the phone at full hour and send a message to an Android Wear watch which than makes a short vibration. I have two users with a Samsung Galaxy S6 with stock Android 5.1.1 and the Sony SW 3 with 5.1.1 who experience a weird bug. At the very first full hour the vibration is at the exact time but all other vibrations are 3 minutes delayed. Sometimes even the first full hour vibration is delayed.

Here is some code:

final Calendar time = Calendar.getInstance();
time.set(Calendar.SECOND, 0);
time.set(Calendar.MILLISECOND, 0);
time.set(Calendar.MINUTE, 0);
time.set(Calendar.HOUR_OF_DAY, time.get(Calendar.HOUR_OF_DAY) + 1);

final Intent hourlyChimeIntent = new Intent(context, HourlyChimeReceiver.class);
hourlyChimeIntent.setAction(key);
final AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, hourlyChimeIntent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);

I acquire a WakeLock in the receiver and then send a message to the Wear watch in a thread. No vibration is missed, they are just 3 minutes late.

I have no other reports about this issue and all my testing devices are working good. I have no Samsung device though.

Any ideas what could cause the 3 minutes delay? Does Samsung ignore setExact and makes my alarm an inexact? How to force exact alarms on Samsungs?

EDIT:

Here is the Android Wear specific code. In the receiver's onReceive method I do this:

final PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock lock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID);
lock.acquire(7L * 1000L);

final GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context).addApi(Wearable.API).build();

new Thread(new Runnable() {
    @Override
    public void run() {
        googleApiClient.blockingConnect();

        long pattern[];
        pattern = new long[] {0L, 500L};

        final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(2000L, TimeUnit.MILLISECONDS);

        if (nodes != null) {
            for (final Node node : nodes.getNodes()) {
                // just send and forget
                Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), "/hourly_chime", Utils.Vibrator.serializeVibratePattern(pattern).getBytes()).await();
            }
        }
    }
}).start();
Apian answered 3/12, 2015 at 19:53 Comment(4)
A thought: it could also be that the alarm is delivered on time, but that a delay is introduced somewhere later. Since your question doesn't state it specifically, I'll ask: are you sure that the actual alarm delivery is delayed?Sir
Hm, thinking about it and I am not 100% sure it is the alarm delivery. I doubt though that opening a connection with a Wear device can take up to three minutes or a Wear message going via bluetooth. I will add the Wear specific code to the question.Apian
i had the same problem, when i wanted my app to update each sunday at 18 o'clock, but it didn't do the job, sometimes it didn't work, sometimes it was delayed, i don't know who makes this work at google, but it is done wrong, and i think by INTENTion [purpose :)]Magdaleno
I have this issue reported only on Samsung devices. There many cases where Samsung changes some core functionality to "optimize" it and breaks it when it works in pure Android.Apian
P
30

The issue seems to occur only on Samsung devices (e.g. Galaxy Grand, S4, S5, S6, Note 3, Note 4) with Lollipop (5.0, 5.1, 5.1.1). It seems that alarms are scheduled inexact when device is on battery with screen off. If device is charging or has screen on during scheduling alarm the issue will not occur.

You can verify if next alarm will be inexact with:

adb shell dumpsys alarm

I didn't find perfect solution for this problem - only workarounds where each has some drawbacks:

  1. Use setAlarmClock instead setExact (see this answer). This works very well (not on all devices), but the issue with this solution is that the alarm will affect the system by showing alarm icon in status bar (if someone doesn't have alarm clock set already) and displaying next alarm scheduled time on alarm widgets etc. Unfortunately while this works on Galaxy Grand with 5.1.1 it doesn't on Galaxy S4 with 5.0.1.
  2. Enable screen before scheduling the alarm (I do this half second before scheduling next alarm to avoid race condition). Of course it is not good solution for every app to enable screen just to schedule next alarm.
  3. One bug report describing similar issue connects it with app package name length! I didn't verify if it really fixes the issue, because changing package name is not an option for already published app.
  4. There is another report where someone claims this can be fixed by using WakefulBroadcastReceiver, but it doesn't work in my case.

BTW This issue drives me crazy :)

Edit: Looks like this issue does not occur when there is keyword "alarm" or "alert" in the app package name (as pointed out by Mathieu H. in comments below).

I was also able to fix the issue manually by disabling App optimization in Battery settings (or in Smart Manager app). It seems it cannot be done programmatically, so you can try asking your users...

Pierro answered 4/12, 2015 at 10:2 Comment(28)
Thank you for this wonderful information. Looks like another great "optimalization" from Samsung. It also explains why the first alarm is on-time and all others are delayed. The only solution I can use is the screen-on. I will report the result.Apian
@shelll, updated answer, looks like first solution does not work on all devices :ODoubt
That solution was not good for me, so I used the screen-on which works kind-of OK. Depends if the the display turn-on fast enough. It is a good enough solotion for me.Apian
@PawełNadolski about item 2 (Enable screen before scheduling ...), How do you turn screen on and how do you schedule it half second before hand? Would you please share the code snippet?Concent
Anything new on this front? I was trying with JobScheduler. It fires more often, bu also not reliably.Afraid
@LukaBradeško Ignore all Galaxy S4 in the market (or enable the screen when scheduling alarm on these devices) if you can and use setAlarmClock if your users do not complain too much about additional alarms on their phone (Galaxy S6 edge users mostly complain). I would also try scheduling time earlier by several minutes and than in chunks less than a minute (I read somewhere that it does not cause delays on such short periods) - it uses more battery, but it just might work.Doubt
I was able to fix this by ensuring that alarms are fired with intervals of less than 15 seconds. Strange. For example, one of my alarms (every 10s) fires correctly, but not the 60s alarm. So I launch the 60s Service when the 10s alarm has fired 6 times. Initial results look positive.Voyeur
About the package name length (point 3), the assumption is almost correct. After many tests, I noticed that if package name contains 'alarm' or 'alert', then AlarmManager triggers alarm on a perfect timing. It seems to be a Samsung bad trick to gain battery life. This works on all devices I tested, as opposed to setAlarmClock which is not working on S4 for example.Insistency
@MathieuH. this is great finding! I need to do more testing, but first test was successful, thanks!Doubt
I confirm that altering the Package name to include Alarm or alert, Alarm Manager worked perfectlyForedeck
@MathieuH my main package name is com.example.myapp, is this solution works when i create a new package like com.example.myapp.alarm?Kippy
@MathieuH. is there any way to implement this solution in an already published app? I've been looking for a solution for years now!Hyssop
@fahmy, as far as I know either you will need to implement point 1 and 2 or create separate app with proper package name that will handle alarms - this it is the part I did not yet evaluated, but it should work. Or take down the app and publish with new package name :/ ...Doubt
I changed the package name to include alarm, initial results look positiveStucco
Android 6.0.1 (Galaxy S6) seems to be affected as wellThreeply
@JeremyLee, I didn't notice the issue on Marshmallow, could that have been effect of Doze Mode?Doubt
@PawełNadolski You mention adding a package should work, but you tell the other guy that publishing with new package name might be the only solution for existing apps? Is it not true that you can just create a package inside your already existing app with the name alarm? Or does it need applicationId to contain alarm instead of the packagename to your class that calls AlarmManager functions?Gresham
@ZeroStatic, actually I didn't verify if adding package with "alarm" in already published app will work. I just assumed it works for application id only. Unfortunately I can't verify if this is the case right now (no device to test).Doubt
Same problem on S7. Adding "alarmmanager" to a package name helps.Phionna
@NikolaiDoronin, wouldn't adding "alarm" be sufficient also on S7?Doubt
@MuhammadBabar, maybe just caring more about battery life than user experience.Doubt
@MathieuH should the 'alarm' and 'alert' words be between dots in the package name or they could be in any place? e.g. com.example.alarm.myapp vs com.example.myalarmapp? Thank you.Apian
@Apian No need to be between dots. For my app, I'm using something like com.example.appalarmInsistency
@PawełNadolski I'm a user for your Blip Blip app (great app by the way, thanks a lot for it), and I'm intrigued by the approach you used on the 'Prevent delays' and 'Prevent delays aggressively' options. Is this where you schedule the alarms in chunks less than a minute? or are you using a different approach here?Winner
@jmart, Thanks :) Prevent delays logs maximum delay and next time schedules alarm earlier by that amount and than sleeps in chunks, but it is much, much more complicated and has it's flaws. Aggressive option just sets maximum from the start to around 8 minutes. Then app sleeps either in chunks or just does Thread.sleep with wakelock. This option may eat a lot of battery , is not easy to implement, works differently on many devices (some devices just kill the app in this mode!), sleeping in chunks not always works. If you can don't go this route :)Doubt
to find other solutions i started to inspect samsung frameworks. actually there are more possible package name patterns like "clock"... Smali Code: pastebin.com/J1XjXxxw i will continue searching for better solutions, but its hard to read SMALI code and converters do not work properlyLaryngology
I have a navigation application. Geofences on Samsung devices after a certain time stop working(on other devices works perfect), seems the problem caused by Smart manager. Can i use push notification to update geofence topology after my app got deactivated by Smart manager?Plutonium
After years, Samsung, instead of removing their "optimization", has ported this "feature" to their Wear OS 3 watches too, so having exact alarms is not possible on their watches anymore :/Apian

© 2022 - 2024 — McMap. All rights reserved.