当前位置:首页 > Android6.0 设备Idle状态(二)AlarmManagerService setIdleUntil接口
Android6.0 设备Idle状态(二)AlarmManagerService setIdleUntil接口
一、set接口对flag中带了FLAG_IDLE_UNTIL的Alarm处理 先来看AlarmManager中:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
public void setIdleUntil(int type, long triggerAtMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, operation, null, null); }
这个接口就是在flag中带了FLAG_IDLE_UNTIL。 我们再来看下AlarmManagerService中的set函数:
[java] view plain copy 在CODE上查看代码片派生到我的代码片 private final IBinder mService = new IAlarmManager.Stub() { @Override
public void set(int type, long triggerAtTime, long windowLength, long interval, int flags, PendingIntent operation, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) { final int callingUid = Binder.getCallingUid(); if (workSource != null) {
getContext().enforcePermission(
android.Manifest.permission.UPDATE_DEVICE_STATS, Binder.getCallingPid(), callingUid, \ }
// No incoming callers can request either WAKE_FROM_IDLE or
// ALLOW_WHILE_IDLE_UNRESTRICTED -- we will apply those later as appropriate.
flags &= ~(AlarmManager.FLAG_WAKE_FROM_IDLE
| AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED);
// Only the system can use FLAG_IDLE_UNTIL -- this is used to tell the alarm // manager when to come out of idle mode, which is only for DeviceIdleController. if (callingUid != Process.SYSTEM_UID) {//如果不是系统应用不能拥有该flag flags &= ~AlarmManager.FLAG_IDLE_UNTIL; }
不是系统应用不能应有该flag。注释的说明也是这个flag只给DeviceIdleController用。
二、setImplLocked函数
继续分析setImplLocked函数
[java] view plain copy 在CODE上查看代码片派生到我的代码片
private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) { if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {//是该flag
// This is a special alarm that will put the system into idle until it goes off. // The caller has given the time they want this to happen at, however we need // to pull that earlier if there are existing alarms that have requested to // bring us out of idle.
if (mNextWakeFromIdle != null) {//第一次该值为null a.when = a.whenElapsed = a.maxWhenElapsed = mNextWakeFromIdle.whenElapsed; }
// Add fuzz to make the alarm go off some time before the actual desired time. final long nowElapsed = SystemClock.elapsedRealtime();
final int fuzz = fuzzForDuration(a.whenElapsed-nowElapsed);// 调整时间 if (fuzz > 0) {
if (mRandom == null) {
mRandom = new Random(); }
final int delta = mRandom.nextInt(fuzz); a.whenElapsed -= delta;//调整时间 if (false) {
Slog.d(TAG, \
Slog.d(TAG, \ Slog.d(TAG, \ Slog.d(TAG, \
Slog.d(TAG, \ }
a.when = a.maxWhenElapsed = a.whenElapsed; }
} else if (mPendingIdleUntil != null) {
// We currently have an idle until alarm scheduled; if the new alarm has // not explicitly stated it wants to run while idle, then put it on hold. if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE
| AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED | AlarmManager.FLAG_WAKE_FROM_IDLE)) == 0) {
mPendingWhileIdleAlarms.add(a); return; } }
int whichBatch = ((a.flags&AlarmManager.FLAG_STANDALONE) != 0)//这块和以前一样没改动
? -1 : attemptCoalesceLocked(a.whenElapsed, a.maxWhenElapsed); if (whichBatch < 0) {
Batch batch = new Batch(a);
addBatchLocked(mAlarmBatches, batch); } else {
Batch batch = mAlarmBatches.get(whichBatch); if (batch.add(a)) {
// The start time of this batch advanced, so batch ordering may // have just been broken. Move it to where it now belongs. mAlarmBatches.remove(whichBatch); addBatchLocked(mAlarmBatches, batch); } }
if (a.alarmClock != null) {
mNextAlarmClockMayChange = true; }
boolean needRebatch = false;
if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
mPendingIdleUntil = a;//如果又改flag的alarm,设置mPendingIdleUntil mConstants.updateAllowWhileIdleMinTimeLocked(); needRebatch = true;// 需要rebatch
} else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
mNextWakeFromIdle = a;
// If this wake from idle is earlier than whatever was previously scheduled, // and we are currently idling, then we need to rebatch alarms in case the idle // until time needs to be updated. if (mPendingIdleUntil != null) { needRebatch = true; } } }
if (!rebatching) {
if (DEBUG_VALIDATE) {
if (doValidate && !validateConsistencyLocked()) {
Slog.v(TAG, \ + \ + \
+ \
+ \ + \ rebatchAllAlarmsLocked(false);
needRebatch = false; } }
if (needRebatch) {
rebatchAllAlarmsLocked(false);//rebatch }
rescheduleKernelAlarmsLocked(); updateNextAlarmClockLocked(); } }
我们先看fuzzForDuration函数:
[java] view plain copy 在CODE上查看代码片派生到我的代码片 static int fuzzForDuration(long duration) {
if (duration < 15*60*1000) {// 小于15分钟
// If the duration until the time is less than 15 minutes, the maximum fuzz // is the duration. return (int)duration;
} else if (duration < 90*60*1000) {//小于90分钟
// If duration is less than 1 1/2 hours, the maximum fuzz is 15 minutes, return 15*60*1000; } else {
// Otherwise, we will fuzz by at most half an hour. return 30*60*1000;//最多半小时 } }
所以上面如果有该flag的alarm,设置下来,需要重新rebatch所有的alarm。
再来看下rebatchAllAlarmsLocked函数
[java] view plain copy 在CODE上查看代码片派生到我的代码片 void rebatchAllAlarmsLocked(boolean doValidate) {
ArrayList
Alarm oldPendingIdleUntil = mPendingIdleUntil;
final long nowElapsed = SystemClock.elapsedRealtime(); final int oldBatches = oldSet.size();
for (int batchNum = 0; batchNum < oldBatches; batchNum++) {//遍历所有的batch Batch batch = oldSet.get(batchNum); final int N = batch.size(); for (int i = 0; i < N; i++) {
reAddAlarmLocked(batch.get(i), nowElapsed, doValidate);// 遍历所有的batch中的alarm重新设置 }
共分享92篇相关文档