Android4.4之后休眠状态下Alarm不准时的问题
Android4.4及之后休眠状态下Alarm不准时的问题
为了减轻功耗,延长电池使用时间。Android 4.4及之后的版本号採用非精准闹钟机制。以及休眠状态下的wakeup类型的alarm不会实时唤醒设备,而会等到机器被物理唤醒时才触发alarm。Android 6.0提供了新的api:setExactAndAllowWhileIdle()部分解决问题,但依旧不能在休眠状态下精准唤醒。
关于alarm api 的支持与使用请參考下图:
(图片来源:https://plus.google.com/+AndroidDevelopers/posts/GdNrQciPwqo)
此外,应用层面不要使用不持有wakelock的BroadcastReceiver,而要使用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_unlockframework 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不准时的问题的更多相关文章
- iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接
如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可以借助VOIP的模式来实现这一需求.但是如果的应用程序并不是正真的VOIP应用,那当你把你的应用提交到AppStore的时候 ...
- [转] iOS应用中通过设置VOIP模式实现休眠状态下socket的长连接
转自:http://blog.csdn.net/missautumn/article/details/17102067 如果你的应用程序需要在设备休眠的时候还能够收到服务器端发送的消息,那我们就可 ...
- win8.1休眠状态下不能进入系统
win8.1下进入睡眠状态出现的问题: 1.合上盖子或者是点击睡眠状态后唤醒进入锁屏界面.可是仅仅能鼠标移动,键盘全然输入不了,出现假死现象,仅仅能强制重新启动. 2.合上盖子再打开无法唤醒屏幕,必须 ...
- android 休眠状态下 后台数据上传
下面来说一下黑屏情况下传递数据: 要实现程序退出之后,仍然可以传递数据,请求网络,必须采用service,service可以保持在后台一直运行,除非系统资源极其匮乏,否则一般来说service是不会被 ...
- Android中Alarm的机制
本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4.首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任 ...
- alarm函数可以定时
貌似是可以的,不过感觉好像这样用不是很好,最好还是用回timer_settimer一些列函数吧,不过既然开了头,就看下alarm怎么用吧. 1. 所需头文件 #include<unistd.h ...
- ubuntu下唤醒或休眠远程计算机
ubuntu让我明白,没有什么完美的东西,要想完美必须付出代价.要么花时间折腾,要么花时间赚钱买系统. 人生也是一样,所以不要期待什么完美.哪有那么好的人,在合适的时间合适的地点让你遇见,还对你有感觉 ...
- linux系统编程之信号(四):alarm和可重入函数
一,alarm() 在将可重入函数之前我们先来了解下alarm()函数使用: #include <unistd.h> unsigned int alarm(unsigned int sec ...
- linux c编程:信号(二) alarm和pause函数
使用alarm函数可以设置一个定时器,在将来的某个时刻该定时器超时.当定时器超时后,产生SIGALRM信号.如果忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程 #include< ...
随机推荐
- Node.js:Web模块、文件系统
一.web模块 Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务.它只需支持HTTP协议.HTML文档格式及URL,与客户端的网络 ...
- 项目笔记:list页面展示与交互设计
1.前台页面: 因为要展示正版和非正版,所以传个Type值过去: //正版序列号库列表 var type = $("input[name='serialNumber']:checked&qu ...
- 图结构练习——BFS——从起始点到目标点的最短步数(邻接表+BFS)
图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描写叙述 在古老的魔兽传说中.有两个军团,一个 ...
- Voice Commands (VCD) Cortana 微软小娜示例
Cortana 样品 您可以创建自定义功能Cortana使用Cortana技能装备或遗留的声音命令(VCD)平台. 在这里,你可以找到相关的样品: Cortana技能装备 目前Cortana技巧是建立 ...
- Centos 安装Apache软件
检查rpm -qa httpd [root@luozhonghua icons]# rpm -qa |grep httpd httpd-2.2.15-30.el6.centos ...
- Linux dig
安装dig: yum install bind-utils dig 常用命令: # dig 最基本的用法dig @server sina.com.cn. # 用 dig 查看 zone 数据传输 di ...
- linux内核——TSS
task state segment,任务状态段. 关于每个cpu对应不同TSS段的问题,如下解释: TSS段主要用在当前的任务从用户态切入内核态时去找到该任务的内核堆栈. 多核上的任务是真正的并发, ...
- 微信小程序弹窗组件
概述 自己封装的一个比较简单微信弹窗小组件,主要就是教会大家对微信小组件的用法和理解,因为微信小程序对组件介绍特别少,所以我就把自己的理解分享给大家 详细 代码下载:http://www.demoda ...
- cpu_test
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- Maven构建项目时index.jsp文件报错
错误为:The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path 原 ...