android - 通过 AlarmManager 创建的警报在 25 天后未运行(= 2^31 - 1 = 2147483647 毫秒)

标签 android alarmmanager android-7.1-nougat

背景:
我有一个在 Android 7.1 上运行的 Android 应用程序。使用 AlarmManage 设置重复任务以在每天的特定时间执行任务。代码如下:

AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long startInMs = getComing9AM();
Intent intent = ...; //an intent to be run when alarm time is up.
PendingIntent ScheduledIntent = PendingIntent.getBroadcast(context, id, intent, 0);
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, startInMs, ScheduledIntent);


private long getComing9AM(){
    long now = System.currentTimeMillis();
    long today = getToday9AM();
    return (now < today? today:getTomorrow9AM());
}

private long getToday9AM(){
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, 9);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    return calendar.getTimeInMillis();
}

private long getTomorrow9AM(){
    return getToday9AM() + 7 * 24 * 3600 * 1000;
}
  • 安卓设备不是手机,而是一个小盒子。在正常操作下,只有电源线插入 WIFI 连接。

  • 问题描述:
  • 计划任务每​​天都运行良好。三周或更长时间后,任务不再运行。
  • 所有其他功能仍在工作,包括 MQTT 客户端通信、IO 操作。

  • 分析结果:
  • 检查问题的模式后,发现自上次启动后大约 25 天,该任务将无法运行。作为一个对数字敏感的数学极客,“25 天”= 2,160,000 秒 = 2,160,000,000 毫秒。而这个值非常接近2^31-1(Integer.MAX_VALUE),相当于24.85天。
  • HDMI 线已插入设备,屏幕显示无输入。
  • 即使在 25 天后(通过 HTTPS)分配了新的计划任务,该任务也不会执行。
  • 将 USB 设备(我尝试使用鼠标)插入设备后,Android 被唤醒(屏幕有显示)。并且安卓已经被唤醒,任务每天都可以正常运行,直到接下来的25天。
  • 使用 ADB 检查 Android 设置,我只能找到一个参数值与 Integer.MAX_VALUE 相符。即(adb shell dumpsys power):
    mMaximumScreenOffTimeoutFromDeviceAdmin=2147483647(强制=假)
    屏幕关闭超时:2147483647 毫秒
  • 根据发现 #5,我尝试将屏幕关闭超时设置为 60000 以尝试重现该问题。但是任务仍然可以照常运行。
  • 它不应该与打盹模式有关,因为设备始终处于充电状态且没有电池。
  • (新发现)dumpsys power 中“mWakefulness”的值为睡着了 24.85 天后。在 24.85 天之前,该值应为 清醒 .
  • (新发现)鉴于 wWakefulness=Asleep arelay,“mLastSleepTime”=now - (startupTimestamp + 24.85day)。

  • 寻求建议:
  • 我想有一些方向来进一步调查这个问题。
  • 我想知道是否有办法在应用程序中模拟唤醒事件? (作为找到根本原因之前的解决方法)。
  • 最佳答案

    I would like to have some direction to further investigate the problem.


    我会想办法对你的代码进行单元测试,以确保它工作正常。您可以定期触发 Intent 并尝试。在单元测试中或通过 adb .您提到了“通过 https”,但也许您需要直接进入“金属”并自己触发方法进行测试。

    I would like to know if there is a way to simulate the waking up event within the application? (as a workaround before finding the root cause).


    您的设备不是手机,所以我不确定它是否能够接收 Firebase 推送通知(或任何形式的),因为您需要为此提供 Google Play 服务,而且还有其他一些东西,但我会尝试手动控制这些事件(外部)以确保 您的代码 不会引起问题。每天早上 9 点发出“哔”声(或打印到 logcat)仍然有效吗?
    如果 AlarmManager 在 NN 天后以某种方式定期中断,那么某些东西要么真的坏了(说实话会很奇怪,7.1 相当旧并且已经使用了很长时间,我希望有人会对此说些什么(? )),或者您的代码行为不端。
    开始隔离事物,你能不能创建一个简单的应用程序,它所做的只是每天早上 9:30 打印一个日志。它仍然有效吗?
    或者会work manager在这里帮助你还是会有其他你不能使用/拥有的依赖项?当然有权衡,因为 WorkManager 与 AlarmManager 不同,并且受到更多限制。

    Even a new scheduled task is assigned after 25days (thru HTTPS), the task will not be executed.


    这也令人费解,因为 AlarmManager 似乎完全停止工作并接收工作。如果您通过 adb 手动广播 Intent ,这项工作是否有效?在那时候?你有不止一种设备吗?它发生在所有人身上吗?
    这是一个非常有趣的问题,我希望我有更具体的东西,但是很少有人会知道 AlarmManager 的内部工作原理。关于谷歌试图在手机上“节省电池”的所有新方法。setExactAndAllowWhenIdle被描述为:

    Unlike other alarms, the system is free to reschedule this type of alarm to happen out of order with any other alarms, even those from the same app. This will clearly happen when the device is idle (since this alarm can go off while idle, when any other alarms from the app will be held until later), but may also happen even when not idle. Note that the OS will allow itself more flexibility for scheduling these alarms than regular exact alarms, since the application has opted into this behavior. When the device is idle it may take even more liberties with scheduling in order to optimize for battery life.


    操作系统可以让自己以某种形式灵活并忽略您的警报吗?嗯不确定。
    最后的评论,你看了吗AlarmManager's source code ?也许里面有暗示。
    最后,这篇长文(应该是评论)并没有真正给你一个解决方案,只是一个让我倾倒想法的开放空间。 :) 如果需要,我会更新;请让我们知道你发现了什么:)
    作为旁注:我会测试您是否可以使用 Gradle 4.x 并可以访问 java.time 的 Java 8 API。 (比日历甚至 util.Date 好得多),或者尝试利用来自 Wharthon 的(现在已存档/弃用但仍可使用一段时间,直到 Gradle 4.x “精简”)ThreeTenABP 抽象来使用相同的 Java8 API(从 ThreeTen 迁移到 java.time 确实需要 10 分钟的查找/替换来更改导入)。
    简而言之,你可以用val tomorrowAt9Am = ZonedDateTime.now().plusDays(1).withHour(9).withMinute(0).withSecond(0).toEpochSecond()编辑:您发现的最后两点(mWakefulness)非常有趣,我会继续寻找。与此同时,我在 Android 代码库中发现了一些上述变量的实例。最有趣的是this one from the AttentionDetector (什么名字);随意to browse all the results

    关于android - 通过 AlarmManager 创建的警报在 25 天后未运行(= 2^31 - 1 = 2147483647 毫秒),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63311972/

    相关文章:

    xamarin - Android 8.0(Oreo) 中的 AlarmManager 和通知

    android - 使用 Alarmmanager 在特定时间启动服务

    Android Nougat 杀死了我在 Oneplus 上的应用程序

    android - 如何在不使用 Market 的情况下将 Android 应用分发给 beta 测试人员

    Android Studio 0.2.9 和新项目

    android - 如何从 Android 上的电话号码中查找联系人的姓名?

    android - Google Play 控制台中令人困惑的 "Upload failed"消息

    java - 报警管理器运行

    java - Android 7.1如何清除通知栏的所有通知?

    Android SDK 版本 25 - android.support v7 :25 gives "No resource found that matches @color/hint_foreground_material_light" Adobe Creative SDK?