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相关函数。

    即:

    android_wake_lock_init
    android_wake_lock_destroy
    android_wake_lock
    android_wake_lock_timeout
    android_wake_unlock

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

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

    public boolean isWakeup(int type)
    {
    return (type & TYPE_NONWAKEUP_MASK) == 0;
    } void setImpl(int type, long triggerAtTime, long windowLength, long interval,
    PendingIntent operation, boolean isStandalone, WorkSource workSource,
    AlarmManager.AlarmClockInfo alarmClock) {
    if (operation == null) {
    Slog.w(TAG, "set/setRepeating ignored because there is no intent");
    return;
    } if (isWakeup(type)) {
    windowLength = AlarmManager.WINDOW_EXACT;
    isStandalone = true;
    }

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

    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
    final long nowRTC) {
    boolean hasWakeup = false;
    // batches are temporally sorted, so we need only pull from the
    // start of the list until we either empty it or hit a batch
    // that is not yet deliverable ArrayList<Alarm> repeatList = new ArrayList<Alarm>();
    ListIterator<Batch> it = mAlarmBatches.listIterator();
    while (it.hasNext()) {
    Batch batch = it.next();
    if (batch.start > nowELAPSED) {
    // Everything else is scheduled for the future
    break;
    } // We will (re)schedule some alarms now; don't let that interfere
    // with delivery of this current batch
    it.remove(); final int N = batch.size();
    for (int i = 0; i < N; i++) {
    Alarm alarm = batch.get(i);
    alarm.count = 1;
    triggerList.add(alarm); // Recurring alarms may have passed several alarm intervals while the
    // phone was asleep or off, so pass a trigger count when sending them.
    if (alarm.repeatInterval > 0) {
    // this adjustment will be zero if we're late by
    // less than one full repeat interval
    alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval; // Also schedule its next recurrence
    repeatList.add(alarm);
    } if (alarm.wakeup) {
    hasWakeup = true;
    mNextWakeup = 0;
    } // We removed an alarm clock. Let the caller recompute the next alarm clock.
    if (alarm.alarmClock != null) {
    mNextAlarmClockMayChange = true;
    }
    }
    } if (repeatList.size() > 0) {
    for (Alarm alarm : repeatList) {
    final long delta = alarm.count * alarm.repeatInterval;
    final long nextElapsed = alarm.whenElapsed + delta;
    setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
    maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
    alarm.repeatInterval, alarm.operation, alarm.windowLength == AlarmManager.WINDOW_EXACT, true,
    alarm.workSource, alarm.alarmClock, alarm.userId);
    }
    } // This is a new alarm delivery set; bump the sequence number to indicate that
    // all apps' alarm delivery classes should be recalculated.
    mCurrentSeq++;
    calculateDeliveryPriorities(triggerList);
    Collections.sort(triggerList, mAlarmDispatchComparator); return hasWakeup;
    }
  • 应用层面使用WakefulBroadcastReceiver:

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

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

    public class AutoUpdateIntentService extends IntentService {
    public AutoUpdateIntentService() {
    super("AutoUpdateIntentService");
    } @Override
    protected void onHandleIntent(Intent intent) {
    String action = intent.getAction(); // do your work here.
    // ... // Release the wake lock provided by the WakefulBroadcastReceiver.
    AutoUpdateAlarmReceiver.completeWakefulIntent(intent);
    }
    }

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. 【实践】require.js + r.js 代码打包压缩初体验

    第二个分享的是学校项目所接触到的新知识,代码压缩 + 代码打包 这次的项目用了require.js 这个插件做模块化管理的工具,所谓模块化就是在开发的过程中将功能划分成一个独立的模块,使代码可读性更强 ...

  2. (剑指Offer)面试题40:数组中只出现一次的数字

    题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 思路: 这道题的简单版本是除了一个数字之外,其他数字都出现了两次,这个很简单,将所有的数异或一遍就 ...

  3. Antlr与Regex

    Antlr与Regex都是文本分析工具. Antlr内部分为词法(Lexer)和语法(Parser),在Antlr中,变量第一个字符大写表示词法,变量第一个字符小写表示语法.词法表示哪些是有效的词,语 ...

  4. C#基础视频教程4.2 如何编写简单的计算器

    用过VB6或者早期代码的人都应该能感觉到,C#目前也没看出来有什么特别之处,所谓的面向对象也没有什么体现.所以我们需要在原有基础上重写一份代码,然后比较两种做法的优缺点.我们在项目上右击添加一个Fun ...

  5. Tengine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性

    简介 Tengine是由淘宝网发起的Web服务器项目.它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性.Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很 ...

  6. Uni2D Unity4.3 2D Skeletal Animation

    http://www.cnblogs.com/zhaoqingqing/p/3602253.html 中文教程:参照 kakashi的CSDN博客 http://blog.csdn.net/kakas ...

  7. java反射--方法反射的基本操作

    方法的反射 1)如何获取某个方法 方法的名称和方法的参数列表才能唯一决定某个方法. 2)方法反射的操作 method.invoke(对象,参数列表). 代码实例: package com.reflec ...

  8. ADBport被占用,adb server is out of date

    wd=adb&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YdPWD1uyP-PHf1ryRYP1Nh0ZwV5Hcvrj ...

  9. js 按enter键提交信息

    http://codeigniter.org.cn/forums/thread-10868-1-1.html function keydown(e) {     var currKey=0,e=e|| ...

  10. Linux命令-文件搜索命令:find

    选项: -name表示按文件名称查找 find /etc -name init 搜索etc目录下面的文件名为init的所有文件(精确搜索) find /etc -name *init* 搜索etc目录 ...