rtc关机闹钟4 AlarmManagerService.java

时间:2023-03-09 04:49:33
rtc关机闹钟4 AlarmManagerService.java

vim base/services/core/java/com/android/server/AlarmManagerService.java

AlarmManager 调用 IAlarmManager, AlarmManagerService 是IAlarmManager的实现

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, "AlarmManager.set");
} // 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) {
flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
} // If the caller is a core system component, and not calling to do work on behalf
// of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED. This means we
// will allow these alarms to go off as normal even while idle, with no timing
// restrictions.
if (callingUid < Process.FIRST_APPLICATION_UID && workSource == null) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
} // If this is an exact time alarm, then it can't be batched with other alarms.
if (windowLength == AlarmManager.WINDOW_EXACT) {
flags |= AlarmManager.FLAG_STANDALONE;
} // If this alarm is for an alarm clock, then it must be standalone and we will
// use it to wake early from idle if needed.
if (alarmClock != null) {
flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
} setImpl(type, triggerAtTime, windowLength, interval, operation,
flags, workSource, alarmClock, callingUid);
}
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
} // Sanity check the window length. This will catch people mistakenly
// trying to pass an end-of-window timestamp rather than a duration.
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
Slog.w(TAG, "Window length " + windowLength
+ "ms suspiciously long; limiting to 1 hour");
windowLength = AlarmManager.INTERVAL_HOUR;
} // Sanity check the recurrence interval. This will catch people who supply
// seconds when the API expects milliseconds.
final long minInterval = mConstants.MIN_INTERVAL;
if (interval > 0 && interval < minInterval) {
Slog.w(TAG, "Suspiciously short interval " + interval
+ " millis; expanding to " + (minInterval/1000)
+ " seconds");
interval = minInterval;
} if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
throw new IllegalArgumentException("Invalid alarm type " + type);
} if (triggerAtTime < 0) {
final long what = Binder.getCallingPid();
Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + callingUid
+ " pid=" + what);
triggerAtTime = 0;
} final long nowElapsed = SystemClock.elapsedRealtime();
final long nominalTrigger = convertToElapsed(triggerAtTime, type);
// Try to prevent spamming by making sure we aren't firing alarms in the immediate future
final long minTrigger = nowElapsed + mConstants.MIN_FUTURITY;
final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger; final long maxElapsed;
if (windowLength == AlarmManager.WINDOW_EXACT) {
maxElapsed = triggerElapsed;
} else if (windowLength < 0) {
maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
// Fix this window in place, so that as time approaches we don't collapse it.
windowLength = maxElapsed - triggerElapsed;
} else {
maxElapsed = triggerElapsed + windowLength;
} synchronized (mLock) {
if (DEBUG_BATCH) {
Slog.v(TAG, "set(" + operation + ") : type=" + type
+ " triggerAtTime=" + triggerAtTime + " win=" + windowLength
+ " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
+ " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, flags, true, workSource, alarmClock, callingUid);
}
} private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
long maxWhen, long interval, PendingIntent operation, int flags,
boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
int uid) {
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
operation, workSource, flags, alarmClock, uid);
removeLocked(operation);
setImplLocked(a, false, doValidate);
} private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
// 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 at an earlier time.
if (mNextWakeFromIdle != null && a.whenElapsed > mNextWakeFromIdle.whenElapsed) {
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, "Alarm when: " + a.whenElapsed);
Slog.d(TAG, "Delta until alarm: " + (a.whenElapsed-nowElapsed));
Slog.d(TAG, "Applied fuzz: " + fuzz);
Slog.d(TAG, "Final delta: " + delta);
Slog.d(TAG, "Final when: " + a.whenElapsed);
}
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;
mConstants.updateAllowWhileIdleMinTimeLocked();
needRebatch = true;
} 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, "Tipping-point operation: type=" + a.type + " when=" + a.when
+ " when(hex)=" + Long.toHexString(a.when)
+ " whenElapsed=" + a.whenElapsed
+ " maxWhenElapsed=" + a.maxWhenElapsed
+ " interval=" + a.repeatInterval + " op=" + a.operation
+ " flags=0x" + Integer.toHexString(a.flags));
rebatchAllAlarmsLocked(false);
needRebatch = false;
}
} if (needRebatch) {
rebatchAllAlarmsLocked(false);
} rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
}
}