因为在个人博客中Android4.4已经比较详细的分析了AlarmManagerService,所以这里主要分析一下差别,在我看来5.1的在AlarmManagerService的改动仍是比较大的。app
先看AlarmManager新增了一个接口:ide
- 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的变化。oop
先从Alarm的设置那块,也就是AlarmManagerService的主线程分析,主要变化最大的是rescheduleKernelAlarmsLocked函数ui
- 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,直接挑选了主要内容:this
- 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这个函数:spa
- 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那块。.net
- * Recomputes the next alarm clock for all users.
- */
- private void updateNextAlarmClockLocked() {
- if (!mNextAlarmClockMayChange) {
- return;
- }
- mNextAlarmClockMayChange = false;
-
- SparseArray<AlarmManager.AlarmClockInfo> nextForUser = mTmpSparseAlarmClockArray;
- nextForUser.clear();
-
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- ArrayList<Alarm> 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);
- }
发送AlarmHandler.SEND_NEXT_ALARM_CLOCK_CHANGED消息,会调用以下函数:线程
- private void sendNextAlarmClockChanged() {
- SparseArray<AlarmManager.AlarmClockInfo> 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:orm
- 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;
- }
- }
- }