因爲在個人博客中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;
- }
- }
- }