Android5.1AlarmManagerService深入分析(Android4.4补充)

由于在我的博客中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; } } }







??

    推荐阅读