由于在我的博客中Android4.4已经比较详细的分析了AlarmManagerService,因此这里主要分析一下差异,在我看来5.1的在AlarmManagerService的改动还是比较大的。
先看AlarmManager新增了一个接口:
public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, operation, null, info);
}
这个接口主要应用自己设置一个新的对象AlarmClockInfo,这个针对多用户的,每个用户也可以在AlarmManagerService中得到自己的下个AlarmClockInfo,可以得到triggertime,pendingIntent。
public AlarmClockInfo getNextAlarmClock() {
return getNextAlarmClock(UserHandle.myUserId());
}
这是AlarmManager,接下来分析下AlarmManagerService中在5.1的变化。
先从Alarm的设置那块,也就是AlarmManagerService的主线程分析,主要变化最大的是rescheduleKernelAlarmsLocked函数
void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm.If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
long nextNonWakeup = 0;
if (mAlarmBatches.size() > 0) {
final Batch firstWakeup = findFirstWakeupBatchLocked();
final Batch firstBatch = mAlarmBatches.get(0);
// always update the kernel alarms, as a backstop against missed wakeups
if (firstWakeup != null) {
mNextWakeup = firstWakeup.start;
setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
}
if (firstBatch != firstWakeup) {//和唤醒的时间不相同,才赋值
nextNonWakeup = firstBatch.start;
}
}
if (mPendingNonWakeupAlarms.size() > 0) {//有没有发送的非唤醒类型的alarm
if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) {
nextNonWakeup = mNextNonWakeupDeliveryTime;
}
}
// always update the kernel alarm, as a backstop against missed wakeups
if (nextNonWakeup != 0) {
mNextNonWakeup = nextNonWakeup;
setLocked(ELAPSED_REALTIME, nextNonWakeup);
}
}
接下来主要分析下AlarmThread的run函数,主要用来发送alarm,直接挑选了主要内容:
boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {//没有wakeup类型的alarm,而且允许延迟(接下来分析)
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
if (mPendingNonWakeupAlarms.size() == 0) {
mStartCurrentDelayTime = nowELAPSED;
mNextNonWakeupDeliveryTime = nowELAPSED//定义下个alarm的发送时间
+ ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2);
}
mPendingNonWakeupAlarms.addAll(triggerList);
mNumDelayedAlarms += triggerList.size();
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
} else {//当alarm有唤醒的
// now deliver the alarm intents;
if there are pending non-wakeup
// alarms, we need to merge them in to the list.note we don't
// just deliver them first because we generally want non-wakeup
// alarms delivered after wakeup alarms.
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
if (mPendingNonWakeupAlarms.size() > 0) {//当有没有发送的非唤醒的alarm,加入发送列表一起发送
calculateDeliveryPriorities(mPendingNonWakeupAlarms);
triggerList.addAll(mPendingNonWakeupAlarms);
Collections.sort(triggerList, mAlarmDispatchComparator);
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
mTotalDelayTime += thisDelayTime;
if (mMaxDelayTime < thisDelayTime) {
mMaxDelayTime = thisDelayTime;
}
mPendingNonWakeupAlarms.clear();
}
deliverAlarmsLocked(triggerList, nowELAPSED);
//发送的部分封装了一个函数,大致和以前一样就不分析了
}
下面我们详细分析下checkAllowNonWakeupDelayLocked这个函数:
long currentNonWakeupFuzzLocked(long nowELAPSED) {
long timeSinceOn = nowELAPSED - mNonInteractiveStartTime;
if (timeSinceOn < 5*60*1000) {
// If the screen has been off for 5 minutes, only delay by at most two minutes.
return 2*60*1000;
} else if (timeSinceOn < 30*60*1000) {
// If the screen has been off for 30 minutes, only delay by at most 15 minutes.
return 15*60*1000;
} else {
// Otherwise, we will delay by at most an hour.
return 60*60*1000;
}
}boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
if (mInteractive) {//屏幕亮着
return false;
}
if (mLastAlarmDeliveryTime <= 0) {
return false;
}
if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) {//有非唤醒类型的alarm未发送,且发送没过期
// This is just a little paranoia, if somehow we have pending non-wakeup alarms
// and the next delivery time is in the past, then just deliver them all.This
// avoids bugs where we get stuck in a loop trying to poll for alarms.
return false;
}
long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime;
//现在距离上次发送的时间差
return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED);
//时间差小于灭屏到现在的一个时间差。
}
接下来分析下,系统更新clockInfo那块。
* Recomputes the next alarm clock for all users.
*/
private void updateNextAlarmClockLocked() {
if (!mNextAlarmClockMayChange) {
return;
}
mNextAlarmClockMayChange = false;
SparseArray nextForUser = mTmpSparseAlarmClockArray;
nextForUser.clear();
final int N = mAlarmBatches.size();
for (int i = 0;
i < N;
i++) {
ArrayList alarms = mAlarmBatches.get(i).alarms;
final int M = alarms.size();
for (int j = 0;
j < M;
j++) {
Alarm a = alarms.get(j);
if (a.alarmClock != null) {
final int userId = a.userId;
// Alarms and batches are sorted by time, no need to compare times here.
if (nextForUser.get(userId) == null) {
nextForUser.put(userId, a.alarmClock);
//uid、alarmClock对应的关系
}
}
}
}// Update mNextAlarmForUser with new values.
final int NN = nextForUser.size();
for (int i = 0;
i < NN;
i++) {
AlarmManager.AlarmClockInfo newAlarm = nextForUser.valueAt(i);
int userId = nextForUser.keyAt(i);
AlarmManager.AlarmClockInfo currentAlarm = mNextAlarmClockForUser.get(userId);
if (!newAlarm.equals(currentAlarm)) {//现在mNextAlarmClockForUser中uid对应的alarmclockinfo不是最新的,需要更新
updateNextAlarmInfoForUserLocked(userId, newAlarm);
}
}// Remove users without any alarm clocks scheduled.
final int NNN = mNextAlarmClockForUser.size();
for (int i = NNN - 1;
i >= 0;
i--) {
int userId = mNextAlarmClockForUser.keyAt(i);
if (nextForUser.get(userId) == null) {//如果现在userId,对应的AlarmClockInfo没有,也要更新
updateNextAlarmInfoForUserLocked(userId, null);
}
}
}private void updateNextAlarmInfoForUserLocked(int userId,
AlarmManager.AlarmClockInfo alarmClock) {
if (alarmClock != null) {
mNextAlarmClockForUser.put(userId, alarmClock);
} else {
mNextAlarmClockForUser.remove(userId);
}mPendingSendNextAlarmClockChangedForUser.put(userId, true);
//将需要更新AlarmClockInfo的userId保存起来
mHandler.removeMessages(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
mHandler.sendEmptyMessage(AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED);
}
【Android5.1AlarmManagerService深入分析(Android4.4补充)】发送AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED消息,会调用如下函数:
private void sendNextAlarmClockChanged() {
SparseArray pendingUsers = mHandlerSparseAlarmClockArray;
pendingUsers.clear();
synchronized (mLock) {
final int N= mPendingSendNextAlarmClockChangedForUser.size();
for (int i = 0;
i < N;
i++) {
int userId = mPendingSendNextAlarmClockChangedForUser.keyAt(i);
pendingUsers.append(userId, mNextAlarmClockForUser.get(userId));
}
mPendingSendNextAlarmClockChangedForUser.clear();
}final int N = pendingUsers.size();
for (int i = 0;
i < N;
i++) {
int userId = pendingUsers.keyAt(i);
AlarmManager.AlarmClockInfo alarmClock = pendingUsers.valueAt(i);
Settings.System.putStringForUser(getContext().getContentResolver(),
Settings.System.NEXT_ALARM_FORMATTED,
formatNextAlarm(getContext(), alarmClock, userId),
userId);
getContext().sendBroadcastAsUser(NEXT_ALARM_CLOCK_CHANGED_INTENT,
new UserHandle(userId));
//发送广播通知各个用户下,其AlarmClockInfo已经改变
}
}
增加了一个监控屏幕亮灭屏的广播receiver:
class InteractiveStateReceiver extends BroadcastReceiver {
public InteractiveStateReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
getContext().registerReceiver(this, filter);
}@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
}
}
}
收到屏幕变化后会调用interactiveStateChangedLocked函数:
void interactiveStateChangedLocked(boolean interactive) {
if (mInteractive != interactive) {
mInteractive = interactive;
final long nowELAPSED = SystemClock.elapsedRealtime();
if (interactive) {//亮屏,发送非唤醒类型的alarm
if (mPendingNonWakeupAlarms.size() > 0) {
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
mTotalDelayTime += thisDelayTime;
if (mMaxDelayTime < thisDelayTime) {
mMaxDelayTime = thisDelayTime;
}
deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
mPendingNonWakeupAlarms.clear();
}
if (mNonInteractiveStartTime > 0) {
long dur = nowELAPSED - mNonInteractiveStartTime;
if (dur > mNonInteractiveTime) {
mNonInteractiveTime = dur;
}
}
} else {//灭屏,更新mNonInteractiveStartTime
mNonInteractiveStartTime = nowELAPSED;
}
}
}
??