[toc]
基于 Android7.1.1 源码,分析 AlarmManagerService 的架构和逻辑,本篇文章来分析下 trigger Alarm 的流程!
0 回顾 在上一篇 set Alarm 文章中,我们知道, set 方法会调用 AlarmMS.rescheduleKernelAlarmsLocked 方法来设置下一个 alarm!
该方法用于设置下一个 Alarm!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 void rescheduleKernelAlarmsLocked () { long nextNonWakeup = 0 ; if (mAlarmBatches.size() > 0 ) { final Batch firstWakeup = findFirstWakeupBatchLocked(); final Batch firstBatch = mAlarmBatches.get(0 ); if (firstWakeup != null && mNextWakeup != firstWakeup.start) { mNextWakeup = firstWakeup.start; mLastWakeupSet = SystemClock.elapsedRealtime(); setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); } if (firstBatch != firstWakeup) { nextNonWakeup = firstBatch.start; } } if (mPendingNonWakeupAlarms.size() > 0 ) { if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { nextNonWakeup = mNextNonWakeupDeliveryTime; } } if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) { mNextNonWakeup = nextNonWakeup; setLocked(ELAPSED_REALTIME, nextNonWakeup); } }
下一个要执行的 wake up alarm 和 no wake up alarm 最终会通过 setLocked 方法进行设置!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private void setLocked (int type, long when) { if (mNativeData != 0 ) { long alarmSeconds, alarmNanoseconds; if (when < 0 ) { alarmSeconds = 0 ; alarmNanoseconds = 0 ; } else { alarmSeconds = when / 1000 ; alarmNanoseconds = (when % 1000 ) * 1000 * 1000 ; } set(mNativeData, type, alarmSeconds, alarmNanoseconds); } else { Message msg = Message.obtain(); msg.what = ALARM_EVENT; mHandler.removeMessages(ALARM_EVENT); mHandler.sendMessageAtTime(msg, when); } }
setLocked 中提供了 2 种方法来设置 Alarm:
一种是通过 Alarm 驱动来设置 Alarm,同时启动一个 AlarmThread 来监听 Alarm 驱动的消息,处理触发的 Alarm!
一种是通过自身的消息循环来设置和触发 Alarm;
正常情况下,Alarm 驱动是存在的,那么,我们先来看看正常情况!
1 AlarmThread.run AlarmThread 内部有一个 while 循环,条件为 true,通过不断循环,来处理来自 Kernel 的消息,下面我们来看卡 AlarmThread 的 run 方法!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 public void run () { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); while (true ) { int result = waitForAlarm(mNativeData); mLastWakeup = SystemClock.elapsedRealtime(); triggerList.clear(); final long nowRTC = System.currentTimeMillis(); final long nowELAPSED = SystemClock.elapsedRealtime(); if ((result & TIME_CHANGED_MASK) != 0 ) { final long lastTimeChangeClockTime; final long expectedClockTime; synchronized (mLock) { lastTimeChangeClockTime = mLastTimeChangeClockTime; expectedClockTime = lastTimeChangeClockTime + (nowELAPSED - mLastTimeChangeRealtime); } if (lastTimeChangeClockTime == 0 || nowRTC < (expectedClockTime-500 ) || nowRTC > (expectedClockTime+500 )) { if (DEBUG_BATCH) { Slog.v(TAG, "Time changed notification from kernel; rebatching" ); } removeImpl(mTimeTickSender); removeImpl(mDateChangeSender); rebatchAllAlarms(); mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); synchronized (mLock) { mNumTimeChanged++; mLastTimeChangeClockTime = nowRTC; mLastTimeChangeRealtime = nowELAPSED; } Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); result |= IS_WAKEUP_MASK; } } if (result != TIME_CHANGED_MASK) { synchronized (mLock) { if (localLOGV) Slog.v( TAG, "Checking for alarms... rtc=" + nowRTC + ", elapsed=" + nowELAPSED); if (WAKEUP_STATS) { if ((result & IS_WAKEUP_MASK) != 0 ) { long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD; int n = 0 ; for (WakeupEvent event : mRecentWakeups) { if (event.when > newEarliest) break ; n++; } for (int i = 0 ; i < n; i++) { mRecentWakeups.remove(); } recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC); } } boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { if (mPendingNonWakeupAlarms.size() == 0 ) { mStartCurrentDelayTime = nowELAPSED; mNextNonWakeupDeliveryTime = nowELAPSED + ((currentNonWakeupFuzzLocked(nowELAPSED)*3 )/2 ); } mPendingNonWakeupAlarms.addAll(triggerList); mNumDelayedAlarms += triggerList.size(); rescheduleKernelAlarmsLocked(); updateNextAlarmClockLocked(); } else { rescheduleKernelAlarmsLocked(); updateNextAlarmClockLocked(); if (mPendingNonWakeupAlarms.size() > 0 ) { 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); } } } else { synchronized (mLock) { rescheduleKernelAlarmsLocked(); } } } }
waitForAlarm 会调用 static jint android_server_AlarmManagerService_waitForAlarm 这个 native 方法,对 /dev/alarm 驱动文件进行操作!
1.1 AlarmMS.waitForAlarm waitForAlarm 方法用来等待 Alarm 驱动的返回,其实阻塞性的!
1 private native int waitForAlarm (long nativeData) ;
该方法最后会调用 navtive 的方法,位于 frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp 文件中:
1.2 AlarmMS.triggerAlarmsLocked triggerAlarmsLocked 方法用于分发那些触发时间已到的 Alarm!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 boolean triggerAlarmsLocked (ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { boolean hasWakeup = false ; while (mAlarmBatches.size() > 0 ) { Batch batch = mAlarmBatches.get(0 ); if (batch.start > nowELAPSED) { break ; } mAlarmBatches.remove(0 ); final int N = batch.size(); for (int i = 0 ; i < N; i++) { Alarm alarm = batch.get(i); if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0 ) { long lastTime = mLastAllowWhileIdleDispatch.get(alarm.uid, 0 ); long minTime = lastTime + mAllowWhileIdleMinTime; if (nowELAPSED < minTime) { alarm.whenElapsed = minTime; if (alarm.maxWhenElapsed < minTime) { alarm.maxWhenElapsed = minTime; } if (RECORD_DEVICE_IDLE_ALARMS) { IdleDispatchEntry ent = new IdleDispatchEntry(); ent.uid = alarm.uid; ent.pkg = alarm.operation.getCreatorPackage(); ent.tag = alarm.operation.getTag("" ); ent.op = "RESCHEDULE" ; ent.elapsedRealtime = nowELAPSED; ent.argRealtime = lastTime; mAllowWhileIdleDispatches.add(ent); } setImplLocked(alarm, true , false ); continue ; } } alarm.count = 1 ; triggerList.add(alarm); if ((alarm.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0 ) { EventLogTags.writeDeviceIdleWakeFromIdle(mPendingIdleUntil != null ? 1 : 0 , alarm.statsTag); } if (mPendingIdleUntil == alarm) { mPendingIdleUntil = null ; rebatchAllAlarmsLocked(false ); restorePendingWhileIdleAlarmsLocked(); } if (mNextWakeFromIdle == alarm) { mNextWakeFromIdle = null ; rebatchAllAlarmsLocked(false ); } if (alarm.repeatInterval > 0 ) { alarm.count += (nowELAPSED - alarm.whenElapsed) / alarm.repeatInterval; final long delta = alarm.count * alarm.repeatInterval; final long nextElapsed = alarm.whenElapsed + delta; setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength, maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), alarm.repeatInterval, alarm.operation, null , null , alarm.flags, true , alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName); } if (alarm.wakeup) { hasWakeup = true ; } if (alarm.alarmClock != null ) { mNextAlarmClockMayChange = true ; } } } mCurrentSeq++; calculateDeliveryPriorities(triggerList); Collections.sort(triggerList, mAlarmDispatchComparator); if (localLOGV) { for (int i=0 ; i<triggerList.size(); i++) { Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i)); } } return hasWakeup; }
1.2.1 AlarmMS.calculateDeliveryPriorities calculateDeliveryPriorities 方法用于计算分发的优先级!参数 alarms 表示所有需要触发的 alarm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 void calculateDeliveryPriorities (ArrayList<Alarm> alarms) { final int N = alarms.size(); for (int i = 0 ; i < N; i++) { Alarm a = alarms.get(i); final int alarmPrio; if (a.operation != null && Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) { alarmPrio = PRIO_TICK; } else if (a.wakeup) { alarmPrio = PRIO_WAKEUP; } else { alarmPrio = PRIO_NORMAL; } PriorityClass packagePrio = a.priorityClass; String alarmPackage = (a.operation != null ) ? a.operation.getCreatorPackage() : a.packageName; if (packagePrio == null ) packagePrio = mPriorities.get(alarmPackage); if (packagePrio == null ) { packagePrio = a.priorityClass = new PriorityClass(); mPriorities.put(alarmPackage, packagePrio); } a.priorityClass = packagePrio; if (packagePrio.seq != mCurrentSeq) { packagePrio.priority = alarmPrio; packagePrio.seq = mCurrentSeq; } else { if (alarmPrio < packagePrio.priority) { packagePrio.priority = alarmPrio; } } } }
这里设置到了如下的几种 alarm 优先级,值越小,优先级越高!
1 2 3 static final int PRIO_TICK = 0 ; static final int PRIO_WAKEUP = 1 ; static final int PRIO_NORMAL = 2 ;
同时有一个集合 mPriorities,用于保存发送者的 package 和其对应 Alarm 优先级:
1 2 3 4 5 6 7 8 9 10 11 12 final class PriorityClass { int seq; int priority; PriorityClass() { seq = mCurrentSeq - 1 ; priority = PRIO_NORMAL; } } final HashMap<String, PriorityClass> mPriorities = new HashMap<>();int mCurrentSeq = 0 ;
PriorityClass 用于表示优先级别!
1.2.2 Collections.sort(triggerList, mAlarmDispatchComparator) 接下来,对 triggerList 进行排序,这里用到了一个比较器 mAlarmDispatchComparator!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() { @Override public int compare (Alarm lhs, Alarm rhs) { if (lhs.priorityClass.priority < rhs.priorityClass.priority) { return -1 ; } else if (lhs.priorityClass.priority > rhs.priorityClass.priority) { return 1 ; } if (lhs.whenElapsed < rhs.whenElapsed) { return -1 ; } else if (lhs.whenElapsed > rhs.whenElapsed) { return 1 ; } return 0 ; } };
首先按照优先级从高到低进行排序,然后按照触发时间从小到大进行排序,如果优先级和时间相同,保持先后顺序不变!
1.3 AlarmMS.checkAllowNonWakeupDelayLocked 该方法用于检查是否需要延迟 no wake up 类型的 Alarm 的分发!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 boolean checkAllowNonWakeupDelayLocked (long nowELAPSED) { if (mInteractive) { return false ; } if (mLastAlarmDeliveryTime <= 0 ) { return false ; } if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime < nowELAPSED) { return false ; } long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime; return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED); }
规则如下:
如果此时处于亮屏状态,无需延迟!
如果此时处于熄屏状态,但是我们还没有分发过任何 Alarm,无需延迟!
如果此时处于熄屏状态,我们之前也分发过 Alarm,那么如果 此时系统中有等待中的 no wake up 类型的 alarm,其分发时间已经过去了,无需延迟;
如果上面三个条件都不满足,那么如果距离上次分发 Alarm 的时间超过了 no wake up 类型 alarm 的最大延迟分发时间,那就无需延迟!
currentNonWakeupFuzzLocked 用来计算了 no wake up 类型 alarm 的最大延迟分发时间
1.3.1 AlarmMS.currentNonWakeupFuzzLocked 该方法是用来计算熄屏幕的时长,然后根据时常,来确定 no wake up 类型的 alarm 的延迟触发的最长时间!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 long currentNonWakeupFuzzLocked (long nowELAPSED) { long timeSinceOn = nowELAPSED - mNonInteractiveStartTime; if (timeSinceOn < 5 *60 *1000 ) { return 2 *60 *1000 ; } else if (timeSinceOn < 30 *60 *1000 ) { return 15 *60 *1000 ; } else { return 60 *60 *1000 ; } }
不多说了!
1.4 AlarmMS.deliverAlarmsLocked deliverAlarmsLocked 方法用于分发已经出发的 Alarm!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void deliverAlarmsLocked (ArrayList<Alarm> triggerList, long nowELAPSED) { mLastAlarmDeliveryTime = nowELAPSED; for (int i=0 ; i<triggerList.size(); i++) { Alarm alarm = triggerList.get(i); final boolean allowWhileIdle = (alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0 ; try { if (localLOGV) { Slog.v(TAG, "sending alarm " + alarm); } if (RECORD_ALARMS_IN_HISTORY) { if (alarm.workSource != null && alarm.workSource.size() > 0 ) { for (int wi=0 ; wi<alarm.workSource.size(); wi++) { ActivityManagerNative.noteAlarmStart( alarm.operation, alarm.workSource.get(wi), alarm.statsTag); } } else { ActivityManagerNative.noteAlarmStart( alarm.operation, alarm.uid, alarm.statsTag); } } mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle); } catch (RuntimeException e) { Slog.w(TAG, "Failure sending alarm." , e); } } }
接下来,我们去看看 DeliveryTracker:
1.5 DeliveryTracker.deliverLocked DeliveryTracker 用以监控和跟踪 Alarm 的分发!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 class DeliveryTracker extends IAlarmCompleteListener .Stub implements PendingIntent .OnFinished { ... ... ... ... public void deliverLocked (Alarm alarm, long nowELAPSED, boolean allowWhileIdle) { if (alarm.operation != null ) { try { alarm.operation.send(getContext(), 0 , mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null , allowWhileIdle ? mIdleOptions : null ); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0 ) { removeImpl(alarm.operation); } return ; } } else { try { if (DEBUG_LISTENER_CALLBACK) { Slog.v(TAG, "Alarm to uid=" + alarm.uid + " listener=" + alarm.listener.asBinder()); } alarm.listener.doAlarm(this ); mHandler.sendMessageDelayed( mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT, alarm.listener.asBinder()), mConstants.LISTENER_TIMEOUT); } catch (Exception e) { if (DEBUG_LISTENER_CALLBACK) { Slog.i(TAG, "Alarm undeliverable to listener " + alarm.listener.asBinder(), e); } return ; } } if (mBroadcastRefCount == 0 ) { setWakelockWorkSource(alarm.operation, alarm.workSource, alarm.type, alarm.statsTag, (alarm.operation == null ) ? alarm.uid : -1 , true ); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1 ).sendToTarget(); } final InFlight inflight = new InFlight(AlarmManagerService.this , alarm.operation, alarm.listener, alarm.workSource, alarm.uid, alarm.packageName, alarm.type, alarm.statsTag, nowELAPSED); mInFlight.add(inflight); mBroadcastRefCount++; if (allowWhileIdle) { mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED); if (RECORD_DEVICE_IDLE_ALARMS) { IdleDispatchEntry ent = new IdleDispatchEntry(); ent.uid = alarm.uid; ent.pkg = alarm.packageName; ent.tag = alarm.statsTag; ent.op = "DELIVER" ; ent.elapsedRealtime = nowELAPSED; mAllowWhileIdleDispatches.add(ent); } } final BroadcastStats bs = inflight.mBroadcastStats; bs.count++; if (bs.nesting == 0 ) { bs.nesting = 1 ; bs.startTime = nowELAPSED; } else { bs.nesting++; } final FilterStats fs = inflight.mFilterStats; fs.count++; if (fs.nesting == 0 ) { fs.nesting = 1 ; fs.startTime = nowELAPSED; } else { fs.nesting++; } if (alarm.type == ELAPSED_REALTIME_WAKEUP || alarm.type == RTC_WAKEUP) { bs.numWakeup++; fs.numWakeup++; if (alarm.workSource != null && alarm.workSource.size() > 0 ) { for (int wi=0 ; wi<alarm.workSource.size(); wi++) { final String wsName = alarm.workSource.getName(wi); ActivityManagerNative.noteWakeupAlarm( alarm.operation, alarm.workSource.get(wi), (wsName != null ) ? wsName : alarm.packageName, alarm.statsTag); } } else { ActivityManagerNative.noteWakeupAlarm( alarm.operation, alarm.uid, alarm.packageName, alarm.statsTag); } } } }
mDeliveryTracker 是 AlarmManagerService 的内部变量,用于监控分发的过程!
这里我们看到,DeliveryTracker 继承了 IAlarmCompleteListener.Stub,这个是由 IAlarmCompleteListener.aidl 文件生成的一个服务端“桩”对象,作用很明显了,用于跨进程通信,即:系统进程和应用进程!
原因很简单,DeliveryTracker 用于监控 Alarm 的分发,所以系统需要知道客户端对 Alarm 的分发和处理结果,所以应用进程那边一定会有 DeliveryTracker 的代理对象的!
同时 DeliveryTracker 还实现了 PendingIntent.OnFinished 接口,用于另外一种分发方式!
我们继续看!
1.5.1 new InFlight 系统会对每一个 Alarm 都创建其 InFlight 对象,并保存到 mInFlight!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 static final class InFlight { final PendingIntent mPendingIntent; final IBinder mListener; final WorkSource mWorkSource; final int mUid; final String mTag; final BroadcastStats mBroadcastStats; final FilterStats mFilterStats; final int mAlarmType; InFlight(AlarmManagerService service, PendingIntent pendingIntent, IAlarmListener listener, WorkSource workSource, int uid, String alarmPkg, int alarmType, String tag, long nowELAPSED) { mPendingIntent = pendingIntent; mListener = listener != null ? listener.asBinder() : null ; mWorkSource = workSource; mUid = uid; mTag = tag; mBroadcastStats = (pendingIntent != null ) ? service.getStatsLocked(pendingIntent) : service.getStatsLocked(uid, alarmPkg); FilterStats fs = mBroadcastStats.filterStats.get(mTag); if (fs == null ) { fs = new FilterStats(mBroadcastStats, mTag); mBroadcastStats.filterStats.put(mTag, fs); } fs.lastTime = nowELAPSED; mFilterStats = fs; mAlarmType = alarmType; } }
1.5.1.1 AlarmMS.getStatsLocked getStatsLocked 用于获得 Alarm 对应的 BroadcastStats 对象!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private final BroadcastStats getStatsLocked (PendingIntent pi) { String pkg = pi.getCreatorPackage(); int uid = pi.getCreatorUid(); return getStatsLocked(uid, pkg); } private final BroadcastStats getStatsLocked (int uid, String pkgName) { ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid); if (uidStats == null ) { uidStats = new ArrayMap<String, BroadcastStats>(); mBroadcastStats.put(uid, uidStats); } BroadcastStats bs = uidStats.get(pkgName); if (bs == null ) { bs = new BroadcastStats(uid, pkgName); uidStats.put(pkgName, bs); } return bs; }
每一个 Alarm 都会有一个 BroadcastStats,用于保存该 Alarm 的分发状态!
同时,AlarmManagerService 也有一个集合:mBroadcastStats,来管理每个 uid 对应的广播分发状态!
1 2 final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats = new SparseArray<ArrayMap<String, BroadcastStats>>();
映射关系:create uid -> ArrayMap:create packageName -> BroadcastStats !
2 分发的流程 前面我们看到,如果 setAlarm 是通过 PendingIntent 的方式来设置的,系统会通过如下方式分发 Alarm!
1 2 3 4 5 alarm.operation.send(getContext(), 0 , mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null , allowWhileIdle ? mIdleOptions : null );
如果 setAlarm 是通过 AlarmListener 的方式来设置的,系统会通过如下方式分发 Alarm!
1 2 3 4 5 6 7 alarm.listener.doAlarm(this ); mHandler.sendMessageDelayed( mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT, alarm.listener.asBinder()), mConstants.LISTENER_TIMEOUT);
下面我们来看看二者的区别!
2.1 Alarm.PendingIntent.send 我们可以看到,对于 PendingIntent,我们会将 Alarm 的重复分发次数通过 Intent.EXTRA_ALARM_COUNT 发送给处理方!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public void send (Context context, int code, @Nullable Intent intent, @Nullable OnFinished onFinished, @Nullable Handler handler, @Nullable String requiredPermission, @Nullable Bundle options) throws CanceledException { try { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) : null ; int res = ActivityManagerNative.getDefault().sendIntentSender( mTarget, code, intent, resolvedType, onFinished != null ? new FinishedDispatcher(this , onFinished, handler) : null , requiredPermission, options); if (res < 0 ) { throw new CanceledException(); } } catch (RemoteException e) { throw new CanceledException(e); } }
这里要注意,我们传入的参数 onFinished 实现对象是 mDeliveryTracker!
这里我们要简单提一下 mTarget,他是 PendingIntent 的内部成员变量,是一个 IIntentSender Binder 对象!我们在调用 PendingIntent.getService 等方法的时候,会有如下的逻辑:
2.1.1 new FinishedDispatcher 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private static class FinishedDispatcher extends IIntentReceiver .Stub implements Runnable { private final PendingIntent mPendingIntent; private final OnFinished mWho; private final Handler mHandler; private Intent mIntent; private int mResultCode; private String mResultData; private Bundle mResultExtras; private static Handler sDefaultSystemHandler; FinishedDispatcher(PendingIntent pi, OnFinished who, Handler handler) { mPendingIntent = pi; mWho = who; if (handler == null && ActivityThread.isSystem()) { if (sDefaultSystemHandler == null ) { sDefaultSystemHandler = new Handler(Looper.getMainLooper()); } mHandler = sDefaultSystemHandler; } else { mHandler = handler; } } }
如果没有传入指定的 Handler,
2.1.2 ActivityMS.sendIntentSender PendingIntent.send 方法最终会调用 AMS.sendIntentSender 方法,当然这里涉及到了 PendingIntent 架构和逻辑,这里不做过多的讨论!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Override public int sendIntentSender (IIntentSender target, int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { if (target instanceof PendingIntentRecord) { return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType, finishedReceiver, requiredPermission, options); } else { if (intent == null ) { Slog.wtf(TAG, "Can't use null intent with direct IIntentSender call" ); intent = new Intent(Intent.ACTION_MAIN); } try { target.send(code, intent, resolvedType, null , requiredPermission, options); } catch (RemoteException e) { } if (finishedReceiver != null ) { try { finishedReceiver.performReceive(intent, 0 , null , null , false , false , UserHandle.getCallingUserId()); } catch (RemoteException e) { } } return 0 ; } }
正常情况下,会调用 PendingIntentRecord.sendWithResult 分发 alarm!
2.1.3 PendingIntentRecord.sendWithResult 1 2 3 4 5 6 public int sendWithResult (int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { return sendInner(code, intent, resolvedType, finishedReceiver, requiredPermission, null , null , 0 , 0 , 0 , options, null ); }
2.1.4 PendingIntentRecord.sendInner 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 int sendInner (int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options, IActivityContainer container) { if (intent != null ) intent.setDefusable(true ); if (options != null ) options.setDefusable(true ); if (whitelistDuration > 0 && !canceled) { owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid, whitelistDuration); } synchronized (owner) { final ActivityContainer activityContainer = (ActivityContainer)container; if (activityContainer != null && activityContainer.mParentActivity != null && activityContainer.mParentActivity.state != ActivityStack.ActivityState.RESUMED) { return ActivityManager.START_CANCELED; } if (!canceled) { sent = true ; if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0 ) { owner.cancelIntentSenderLocked(this , true ); canceled = true ; } Intent finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0 ; if (!immutable) { if (intent != null ) { int changes = finalIntent.fillIn(intent, key.flags); if ((changes & Intent.FILL_IN_DATA) == 0 ) { resolvedType = key.requestResolvedType; } } else { resolvedType = key.requestResolvedType; } flagsMask &= ~Intent.IMMUTABLE_FLAGS; flagsValues &= flagsMask; finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); } else { resolvedType = key.requestResolvedType; } final long origId = Binder.clearCallingIdentity(); boolean sendFinish = finishedReceiver != null ; int userId = key.userId; if (userId == UserHandle.USER_CURRENT) { userId = owner.mUserController.getCurrentOrTargetUserIdLocked(); } int res = 0 ; switch (key.type) { case ActivityManager.INTENT_SENDER_ACTIVITY: if (options == null ) { options = key.options; } else if (key.options != null ) { Bundle opts = new Bundle(key.options); opts.putAll(options); options = opts; } try { if (key.allIntents != null && key.allIntents.length > 1 ) { Intent[] allIntents = new Intent[key.allIntents.length]; String[] allResolvedTypes = new String[key.allIntents.length]; System.arraycopy(key.allIntents, 0 , allIntents, 0 , key.allIntents.length); if (key.allResolvedTypes != null ) { System.arraycopy(key.allResolvedTypes, 0 , allResolvedTypes, 0 , key.allResolvedTypes.length); } allIntents[allIntents.length-1 ] = finalIntent; allResolvedTypes[allResolvedTypes.length-1 ] = resolvedType; owner.startActivitiesInPackage(uid, key.packageName, allIntents, allResolvedTypes, resultTo, options, userId); } else { owner.startActivityInPackage(uid, key.packageName, finalIntent, resolvedType, resultTo, resultWho, requestCode, 0 , options, userId, container, null ); } } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startActivity intent" , e); } break ; case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: if (key.activity.task.stack != null ) { key.activity.task.stack.sendActivityResultLocked(-1 , key.activity, key.who, key.requestCode, code, finalIntent); } break ; case ActivityManager.INTENT_SENDER_BROADCAST: try { int sent = owner.broadcastIntentInPackage(key.packageName, uid, finalIntent, resolvedType, finishedReceiver, code, null , null , requiredPermission, options, (finishedReceiver != null ), false , userId); if (sent == ActivityManager.BROADCAST_SUCCESS) { sendFinish = false ; } } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startActivity intent" , e); } break ; case ActivityManager.INTENT_SENDER_SERVICE: try { owner.startServiceInPackage(uid, finalIntent, resolvedType, key.packageName, userId); } catch (RuntimeException e) { Slog.w(TAG, "Unable to send startService intent" , e); } catch (TransactionTooLargeException e) { res = ActivityManager.START_CANCELED; } break ; } if (sendFinish && res != ActivityManager.START_CANCELED) { try { finishedReceiver.performReceive(new Intent(finalIntent), 0 , null , null , false , false , key.userId); } catch (RemoteException e) { } } Binder.restoreCallingIdentity(origId); return res; } } return ActivityManager.START_CANCELED; }
2.2 Alarm.Listener.doAlarm Alarm.Listener 是一个 Binder 对象,其服务端是应用进程的 ListenerWrapper 对象,之前我们知道 ListenerWrapper 实现了 IAlarmListener.Stub:
3 特殊的触发路径 如果没有 Alarm 驱动,那么我们知道 Alarm 的触发是通过内部的一个 AlarmHandler 实现的:
1 2 3 4 5 6 7 8 9 10 private void setLocked (int type, long when) { if (mNativeData != 0 ) { ... ... ... } else { Message msg = Message.obtain(); msg.what = ALARM_EVENT; mHandler.removeMessages(ALARM_EVENT); mHandler.sendMessageAtTime(msg, when); } }
可以看到,最后发送的是 ALARM_EVENT 给 AlarmHandler:
3.1 AlarmHandler.handleMessage[ALARM_EVENT] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public void handleMessage (Message msg) { switch (msg.what) { case ALARM_EVENT: { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); synchronized (mLock) { final long nowRTC = System.currentTimeMillis(); final long nowELAPSED = SystemClock.elapsedRealtime(); triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); updateNextAlarmClockLocked(); } for (int i=0 ; i<triggerList.size(); i++) { Alarm alarm = triggerList.get(i); try { alarm.operation.send(); } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0 ) { removeImpl(alarm.operation); } } } break ; } } }
这个方法逻辑很简单,不多说了!