Android4.4及之后休眠状态下Alarm不准时的问题

为了减轻功耗,延长电池使用时间。Android 4.4及之后的版本号採用非精准闹钟机制。以及休眠状态下的wakeup类型的alarm不会实时唤醒设备,而会等到机器被物理唤醒时才触发alarmAndroid 6.0提供了新的api:setExactAndAllowWhileIdle()部分解决问题,但依旧不能在休眠状态下精准唤醒。

关于alarm api 的支持与使用请參考下图:



(图片来源:https://plus.google.com/+AndroidDevelopers/posts/GdNrQciPwqo)

此外,应用层面不要使用不持有wakelockBroadcastReceiver,而要使用WakefulBroadcastReceiver

为了修复这个问题。以5.0.2版本号为例,须要改动内核下的alarm-dev.c以及framework下的AlarmManagerService。

  • 内核 alarm-dev.c:其原因是使用普通的static struct wakeup_source alarm_wake_lock;,而非带有WAKE_LOCK_SUSPEND类别信息的struct wake_lock,而且须要使用带有android_前缀的wakeup lock相关函数。

    即:

    1. android_wake_lock_init
    2. android_wake_lock_destroy
    3. android_wake_lock
    4. android_wake_lock_timeout
    5. android_wake_unlock

    而非普通的wake lock操作函数:

    1. wake_lock_init
    2. wake_lock_destroy
    3. wake_lock
    4. wake_lock_timeout
    5. wake_unlock
  • framework AlarmManagerService.java:须要将wakeup类型的alarm特殊处理:即精准闹铃。在setImpl中加入例如以下代码:

    1. public boolean isWakeup(int type)
    2. {
    3. return (type & TYPE_NONWAKEUP_MASK) == 0;
    4. }
    5. void setImpl(int type, long triggerAtTime, long windowLength, long interval,
    6. PendingIntent operation, boolean isStandalone, WorkSource workSource,
    7. AlarmManager.AlarmClockInfo alarmClock) {
    8. if (operation == null) {
    9. Slog.w(TAG, "set/setRepeating ignored because there is no intent");
    10. return;
    11. }
    12. if (isWakeup(type)) {
    13. windowLength = AlarmManager.WINDOW_EXACT;
    14. isStandalone = true;
    15. }

    并在alarm被触发时多取几个满足条件的batch做处理:

    1. boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
    2. final long nowRTC) {
    3. boolean hasWakeup = false;
    4. // batches are temporally sorted, so we need only pull from the
    5. // start of the list until we either empty it or hit a batch
    6. // that is not yet deliverable
    7. ArrayList<Alarm> repeatList = new ArrayList<Alarm>();
    8. ListIterator<Batch> it = mAlarmBatches.listIterator();
    9. while (it.hasNext()) {
    10. Batch batch = it.next();
    11. if (batch.start > nowELAPSED) {
    12. // Everything else is scheduled for the future
    13. break;
    14. }
    15. // We will (re)schedule some alarms now; don't let that interfere
    16. // with delivery of this current batch
    17. it.remove();
    18. final int N = batch.size();
    19. for (int i = 0; i < N; i++) {
    20. Alarm alarm = batch.get(i);
    21. alarm.count = 1;
    22. triggerList.add(alarm);
    23. // Recurring alarms may have passed several alarm intervals while the
    24. // phone was asleep or off, so pass a trigger count when sending them.
    25. if (alarm.repeatInterval > 0) {
    26. // this adjustment will be zero if we're late by
    27. // less than one full repeat interval
    28. alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval;
    29. // Also schedule its next recurrence
    30. repeatList.add(alarm);
    31. }
    32. if (alarm.wakeup) {
    33. hasWakeup = true;
    34. mNextWakeup = 0;
    35. }
    36. // We removed an alarm clock. Let the caller recompute the next alarm clock.
    37. if (alarm.alarmClock != null) {
    38. mNextAlarmClockMayChange = true;
    39. }
    40. }
    41. }
    42. if (repeatList.size() > 0) {
    43. for (Alarm alarm : repeatList) {
    44. final long delta = alarm.count * alarm.repeatInterval;
    45. final long nextElapsed = alarm.whenElapsed + delta;
    46. setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
    47. maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
    48. alarm.repeatInterval, alarm.operation, alarm.windowLength == AlarmManager.WINDOW_EXACT, true,
    49. alarm.workSource, alarm.alarmClock, alarm.userId);
    50. }
    51. }
    52. // This is a new alarm delivery set; bump the sequence number to indicate that
    53. // all apps' alarm delivery classes should be recalculated.
    54. mCurrentSeq++;
    55. calculateDeliveryPriorities(triggerList);
    56. Collections.sort(triggerList, mAlarmDispatchComparator);
    57. return hasWakeup;
    58. }
  • 应用层面使用WakefulBroadcastReceiver:

    1. import android.support.v4.content.WakefulBroadcastReceiver;
    2. public class AutoUpdateAlarmReceiver extends WakefulBroadcastReceiver {
    3. @Override
    4. public void onReceive(Context context, Intent intent) {
    5. // Start the service, keeping the device awake while the service is
    6. // launching. This is the Intent to deliver to the service.
    7. Intent service = new Intent(context, AutoUpdateIntentService.class);
    8. service.setAction(intent.getAction());
    9. startWakefulService(context, service);
    10. }
    11. }

    对应的IntentService例如以下所看到的:

    1. public class AutoUpdateIntentService extends IntentService {
    2. public AutoUpdateIntentService() {
    3. super("AutoUpdateIntentService");
    4. }
    5. @Override
    6. protected void onHandleIntent(Intent intent) {
    7. String action = intent.getAction();
    8. // do your work here.
    9. // ...
    10. // Release the wake lock provided by the WakefulBroadcastReceiver.
    11. AutoUpdateAlarmReceiver.completeWakefulIntent(intent);
    12. }
    13. }

Android4.4之后休眠状态下Alarm不准时的问题的更多相关文章

  1. iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接

    如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可以借助VOIP的模式来实现这一需求.但是如果的应用程序并不是正真的VOIP应用,那当你把你的应用提交到AppStore的时候 ...

  2. [转] iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接

      转自:http://blog.csdn.net/missautumn/article/details/17102067 如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可 ...

  3. win8.1休眠状态下不能进入系统

    win8.1下进入睡眠状态出现的问题: 1.合上盖子或者是点击睡眠状态后唤醒进入锁屏界面.可是仅仅能鼠标移动,键盘全然输入不了,出现假死现象,仅仅能强制重新启动. 2.合上盖子再打开无法唤醒屏幕,必须 ...

  4. android 休眠状态下 后台数据上传

    下面来说一下黑屏情况下传递数据: 要实现程序退出之后,仍然可以传递数据,请求网络,必须采用service,service可以保持在后台一直运行,除非系统资源极其匮乏,否则一般来说service是不会被 ...

  5. Android中Alarm的机制

    本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4.首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任 ...

  6. alarm函数可以定时

    貌似是可以的,不过感觉好像这样用不是很好,最好还是用回timer_settimer一些列函数吧,不过既然开了头,就看下alarm怎么用吧. 1. 所需头文件  #include<unistd.h ...

  7. ubuntu下唤醒或休眠远程计算机

    ubuntu让我明白,没有什么完美的东西,要想完美必须付出代价.要么花时间折腾,要么花时间赚钱买系统. 人生也是一样,所以不要期待什么完美.哪有那么好的人,在合适的时间合适的地点让你遇见,还对你有感觉 ...

  8. linux系统编程之信号(四):alarm和可重入函数

    一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...

  9. linux c编程:信号(二) alarm和pause函数

    使用alarm函数可以设置一个定时器,在将来的某个时刻该定时器超时.当定时器超时后,产生SIGALRM信号.如果忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程 #include< ...

随机推荐

  1. .net平台借助第三方推送服务在推送Android消息(极光推送)

    最近做的.net项目(Windows Service)需要向Android手机发送推送消息,真是有点困难,没有搞过就不停的搜文档,最后看到了一个开源项目PushSharp,可以在.net平台推送IOS ...

  2. mysql的数据恢复

    转载自:http://ourmysql.com/archives/1293 数据库数据被误删除是经常看到的事情,数据的恢复也就自然成为了DBA很重要的一门基本功夫,比较笨拙的办法是拉出历史的备份到另外 ...

  3. 【Hadoop基础】hadoop fs 命令

    1,hadoop fs –fs [local | <file system URI>]:声明hadoop使用的文件系统,如果不声明的话,使用当前配置文件配置的,按如下顺序查找:hadoop ...

  4. UVA 270 Lining Up (几何 判断共线点)

     Lining Up  ``How am I ever going to solve this problem?" said the pilot. Indeed, the pilot was ...

  5. UNIX网络编程读书笔记:基本SCTP套接口编程

    概述 SCTP是一个较新的传输协议,于2000年在IETF得到标准化(TCP是在1981年标准化的).它最初是为满足不断增长的IP电话市场设计的:具体地说,就是穿越因特网传输电话信令. SCTP是一个 ...

  6. UVA 10620 - A Flea on a Chessboard(鸽笼原理)

    UVA 10620 - A Flea on a Chessboard 题目链接 题意:给定一个跳蚤位置和移动方向.如今在一个国际象棋棋盘上,左下角为黑格,一个格子为s*s,推断是否能移动到白格子.问要 ...

  7. knockoutjs -- all built-in buildings

    所有可用的binding值 文字和显示:visible, text, html, css, style, attr 流程控制:foreach, if, ifnot, with form字段:click ...

  8. pageEncoding和ContextType区别

    http://blog.csdn.net/kerrywang/article/details/4454895 pageEncoding        在JSP标准的语法中,如果 pageEncodin ...

  9. js表单验证控制代码大全

    http://www.cnblogs.com/SAL2928/archive/2008/10/24/1319020.html目录: 1:js 字符串长度限制.判断字符长度.js限制输入.限制不能输入. ...

  10. Android画图之抗锯齿

    在画图的时候,图片如果旋转或缩放之后,总是会出现那些华丽的锯齿.其实Android自带了解决方式.    方法一:给Paint加上抗锯齿标志.然后将Paint对象作为参数传给canvas的绘制方法. ...