轉載請註明出處:http://blog.csdn.net/singwhatiwanna/article/details/18448997java
本次給你們分析的是Android中Alarm的機制以及它和Binder的交互,所用源碼爲最新的Android4.4。由於Alarm的功能都是經過Binder來完成的,因此,介紹Alarm以前必需要先介紹下它是如何調用Binder來完成定時功能的。因爲內容較多,本文會比較長,在文章結構安排上是這樣的:首先簡單介紹如何使用Alarm並給出其工做原理,接着分析Alarm和Timer以及Handler在完成定時任務上的差異,而後分析Alarm與Binder的交互,最後分析Alarm機制的源碼。android
Alarm是android提供的用於完成鬧鐘式定時任務的類,系統經過AlarmManager來管理全部的Alarm,Alarm支持一次性定時任務和循環定時任務,它的使用方式很簡單,這裏很少作介紹,只給出一個簡單的示例:數據庫
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(getApplicationContext(), TestActivity.class); PendingIntent pendIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); //5秒後發送廣播,只發送一次 int triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000; alarmMgr.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, pendIntent);
相同點:app
三者均可以完成定時任務,都支持一次性定時和循環定時(注:Handler能夠間接支持循環定時任務)ide
不一樣點:oop
Handler和Timer在定時上是相似的,兩者在系統休眠的狀況下沒法正常工做,定時任務不會按時觸發。Alarm在系統休眠的狀況下能夠正常工做,而且還能夠決定是否喚醒系統,同時Alarm在自身不啓動的狀況下仍能正常收到定時任務提醒,可是當系統重啓或者應用被殺死的狀況下,Alarm定時任務會被取消。另外,從Android4.4開始,Alarm事件默認採用非精準方式,即定時任務可能會有小範圍的提早或延後,固然咱們能夠強制採用精準方式,而在此以前,Alarm事件都是精準方式。源碼分析
Alarm由AlarmManager來管理,從使用方式來看,AlarmManager很簡單,咱們只要獲得了AlarmManager的對象,就能夠調用set方法來設定定時任務了,而如何獲得AlarmManager對象呢?也很簡單,AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);下面咱們去看看AlarmManager的set方法,固然AlarmManager還有setRepeating方法,可是兩者是相似的。爲了更好地理解下面的內容,須要你瞭解AIDL,若是你還不瞭解,請參看android跨進程通訊(IPC):使用AIDL。fetch
code:AlarmManager#setui
public void set(int type, long triggerAtMillis, PendingIntent operation) { setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null); } public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis, PendingIntent operation, WorkSource workSource) { setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource); } private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis, PendingIntent operation, WorkSource workSource) { if (triggerAtMillis < 0) { /* NOTYET if (mAlwaysExact) { // Fatal error for KLP+ apps to use negative trigger times throw new IllegalArgumentException("Invalid alarm trigger time " + triggerAtMillis); } */ triggerAtMillis = 0; } try { //定時任務實際上都有mService來完成,也就是說AlarmManager只是一個空殼 //從下面的構造方法能夠看出,這個mService是IAlarmManager類型的,而IAlarmManager是一個接口 //若是你們瞭解AIDL就應該知道IAlarmManager應該是一個AIDL接口 mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource); } catch (RemoteException ex) { } } AlarmManager(IAlarmManager service, Context ctx) { mService = service; final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion; mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT); }
說明:我對代碼進行了註釋,從註釋能夠看出,如今咱們須要去找到這個mService,其實我已經幫你們找到了,它就是AlarmManagerService,看下它的類的聲明:this
class AlarmManagerService extends IAlarmManager.Stub
很顯然,AlarmManagerService的確實現了IAlarmManager接口,爲何是顯然呢?由於按照AIDL的規範,IAlarmManager.Stub是按照以下這種方式聲明的:
public static abstract class Stub extends Binder implements IAlarmManager { public static IAlarmManager asInterface(IBinder obj) ... }
可見這個Stub類就是一個普通的Binder,只不過它實現了IAlarmManager接口。它還有一個靜態方法asInterface,這個方法頗有用,經過它,咱們就能夠將IBinder對象轉換成IAlarmManager的實例,進而經過實例來調用其方法。什麼是Binder?這個還真很差說,可是咱們要知道Binder在Android系統中有大量的應用,大部分Manager都經過Binder來實現(包括AlarmManager),而Service和AIDL也是經過Binder來實現調用的。至於Binder和IBinder的關係,很簡單,就是Binder實現了IBinder接口。因爲AlarmManagerService繼承了IAlarmManager.Stub,因此AlarmManagerService也至關於實現了IAlarmManager接口,因此很顯然,AlarmManagerService就是AlarmManager中用於和其交互的mService。不過,尚未完,由於上面的結論不是我瞎猜的,是有代碼層面的依據的,下面我將帶領你們一塊兒去探索尋找mService的過程,經過這個過程,咱們會對Binder機制有更加深入的認識。
首先Dalvik虛擬機會在SystemServer中建立一個叫作ServerThread的線程並調用它的initAndLoop方法,在initAndLoop方法中會建立主線程Looper和初始化各類Manager所對應的Binder服務,咱們所常見的Binder服務如WindowManagerService、AlarmManagerService、PowerManagerService等均在這裏建立並加入到ServiceManager中進行統一管理。而咱們經過getSystemService方式來獲得各類Manager的工做主要是在ContextImpl中完成的,不過LayoutInflater、WindowManager以及SearchManager除外。經過ContextImpl咱們能夠知道各類Manager和Binder服務的一一對應關係,好比AlarmManager對應AlarmManagerService、WindowManager對應WindowManagerService。
上面只是結論,爲了真正搞清楚各類Manager所對應的Binder服務,下面將要看一系列代碼,首先看SystemServer的代碼:
code:SystemServer
public class SystemServer { private static final String TAG = "SystemServer"; public static final int FACTORY_TEST_OFF = 0; public static final int FACTORY_TEST_LOW_LEVEL = 1; public static final int FACTORY_TEST_HIGH_LEVEL = 2; static Timer timer; static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr // The earliest supported time. We pick one day into 1970, to // give any timezone code room without going into negative time. private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000; /** * Called to initialize native system services. * 初始化本地系統服務,jni方法 */ private static native void nativeInit(); //main方法,由底層調用 public static void main(String[] args) { if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { // If a device's clock is before 1970 (before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it // shortly. Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } if (SamplingProfilerIntegration.isEnabled()) { SamplingProfilerIntegration.start(); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { SamplingProfilerIntegration.writeSnapshot("system_server", null); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // Mmmmmm... more memory! dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); Environment.setUserRequired(true); System.loadLibrary("android_servers"); Slog.i(TAG, "Entered the Android system server!"); // 初始化本地服務. nativeInit(); //這裏是關鍵,ServerThread被建立,同時其initAndLoop被調用 ServerThread thr = new ServerThread(); thr.initAndLoop(); } }
接着看ServerThread的initAndLoop方法,該方法中,主線程Looper會被建立,各類Binder服務會被建立。該方法太長,我進行了截斷,只展出咱們所關心的代碼。
code:ServerThread#initAndLoop
public void initAndLoop() { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis()); //主線程Looper被建立 Looper.prepareMainLooper(); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); BinderInternal.disableBackgroundScheduling(true); android.os.Process.setCanSelfBackground(false); ...此處省略 //下面是各類Binder服務,從名字咱們應該可以大體看出它們所對應的Manager Installer installer = null; AccountManagerService accountManager = null; ContentService contentService = null; LightsService lights = null; PowerManagerService power = null; DisplayManagerService display = null; BatteryService battery = null; VibratorService vibrator = null; AlarmManagerService alarm = null; MountService mountService = null; NetworkManagementService networkManagement = null; NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; ConnectivityService connectivity = null; WifiP2pService wifiP2p = null; WifiService wifi = null; NsdService serviceDiscovery= null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; BluetoothManagerService bluetooth = null; DockObserver dock = null; UsbService usb = null; SerialService serial = null; TwilightService twilight = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; NetworkTimeUpdateService networkTimeUpdater = null; CommonTimeManagementService commonTimeMgmtService = null; InputManagerService inputManager = null; TelephonyRegistry telephonyRegistry = null; ConsumerIrService consumerIr = null; ...此處省略 Slog.i(TAG, "Alarm Manager"); //這裏AlarmManager對應的Binder服務被建立 alarm = new AlarmManagerService(context); //將AlarmManagerService加入ServiceManager中統一管理 ServiceManager.addService(Context.ALARM_SERVICE, alarm); Slog.i(TAG, "Init Watchdog"); Watchdog.getInstance().init(context, battery, power, alarm, ActivityManagerService.self()); Watchdog.getInstance().addThread(wmHandler, "WindowManager thread"); Slog.i(TAG, "Input Manager"); inputManager = new InputManagerService(context, wmHandler); Slog.i(TAG, "Window Manager"); //這裏WindowManager所對應的Binder服務被建立 wm = WindowManagerService.main(context, power, display, inputManager, wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, !firstBoot, onlyCore); //將WindowManagerService加入ServiceManager中統一管理 ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); ActivityManagerService.self().setWindowManager(wm); ...此處省略 }
說明:針對上述代碼,我要說明一下,首先其建立的各類Binder服務其實並非真正的服務,說它們是Binder比較恰當,由於它們的確繼承自Binder而不是Service;另外一點就是ServiceManager其實也僅僅是個殼子,真正的工做是經過其Binder服務ServiceManagerNative來完成的,ServiceManager提供的工廠方法addService和getService均在ServiceManagerNative中經過代理來實現。
到此爲止,咱們已經知道各類Binder服務的建立過程,下面咱們要看一下Manager是如何和其Binder服務關聯上的,再回到getSystemService方法。首先咱們要知道Activity的繼承關係,以下圖所示:
再看以下代碼,觀察下它們中的getSystemService方法是如何實現的
code:各類getSystemService方法
//#Context public abstract Object getSystemService(String name); //#ContextWrapper @Override public Object getSystemService(String name) { return mBase.getSystemService(name); } //#ContextThemeWrapper @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(mBase).cloneInContext(this); } return mInflater; } return mBase.getSystemService(name); } //#Activity @Override public Object getSystemService(String name) { if (getBaseContext() == null) { throw new IllegalStateException( "System services not available to Activities before onCreate()"); } if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } else if (SEARCH_SERVICE.equals(name)) { ensureSearchManager(); return mSearchManager; } return super.getSystemService(name); }
說明:經過上述代碼能夠看出LayoutInflater、WindowManager以及SearchManager的處理比較特殊,直接在方法中返回對象,剩下的全部Manager將經過mBase.getSystemService(name)返回,如今問題轉移到mBase上面,mBase是什麼呢?我已經查清楚了,Activity的mBase就是ContextImpl對象,何以見得?請看下面分析
不知道你們對我寫的另一篇源碼分析是否有印象:Android源碼分析-Activity的啓動過程,在這篇文章中我指出:Activity的最終啓動過程由ActivityThread中的performLaunchActivity方法來完成,在performLaunchActivity中,Activity的mBase將被賦值爲ContextImpl對象,下面經過代碼來講明:
code:mBase的賦值過程
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... if (activity != null) { //這裏的appContext就是ContextImpl對象 Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); //經過Activity的attach方法將ContextImpl對象賦值給mBase activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config); ... } ... } private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { //很顯然,此方法返回的就是ContextImpl對象 ContextImpl appContext = new ContextImpl(); appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); Context baseContext = appContext; ... return baseContext; } final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { //將context賦值給mBase,這裏的context就是performLaunchActivity中的appContext,即ContextImpl對象 attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); ... } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); //這裏很顯然,對mBase進行賦值 mBase = newBase; }
說明:看了上面的代碼,咱們已經知道,mBase的確是ContextImpl對象。上面我提到:除了LayoutInflater、WindowManager以及SearchManager,剩下的全部Manager將經過mBase.getSystemService(name)返回,那麼如今,咱們去看下ContextImpl中的getSystemService方法。
code:ContextImpl#getSystemService
class ContextImpl extends Context { ... @Override public Object getSystemService(String name) { //首先從SYSTEM_SERVICE_MAP根據服務名獲得一個fetcher對象 //其中SYSTEM_SERVICE_MAP是一個HashMap,而後再經過fetcher去取service ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); } ... }
說明:看了ContextImpl的getSystemService方法,發現失望了,尚未找到真正的實現,看來還要去看這個fetcher是怎麼回事,下面請看代碼:
code:服務註冊過程和fetcher
//一個哈希表,用來根據服務名存儲對應服務的ServiceFetcher(能夠理解爲經過ServiceFetcher能夠獲得服務) private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>(); //註冊服務,將服務的fetcher存到哈希表中 private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } //靜態代碼塊,註冊各類服務 //也就是說,ContextImpl這個類被加載的時候就會把以下的各類服務的fetcher加入到哈希表中 //這樣咱們經過getSystemService就能夠獲得一個服務的fetcher,再經過fetcher去獲得服務的對象 static { registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { return AccessibilityManager.getInstance(ctx); }}); registerService(CAPTIONING_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { return new CaptioningManager(ctx); }}); registerService(ACCOUNT_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(ACCOUNT_SERVICE); IAccountManager service = IAccountManager.Stub.asInterface(b); return new AccountManager(ctx, service); }}); registerService(ACTIVITY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); //這裏是Alarm服務的註冊 registerService(ALARM_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { /**還記得ALARM_SERVICE嗎? * alarm = new AlarmManagerService(context); * 將AlarmManagerService加入ServiceManager中統一管理 * ServiceManager.addService(Context.ALARM_SERVICE, alarm); */ //經過ServiceManager的getService獲得Alarm服務,很顯然,下面的b就是AlarmManagerService對象 IBinder b = ServiceManager.getService(ALARM_SERVICE); //還記得AlarmManager中的mService嗎?就是這裏的service,很顯然它是一個Binder服務 //分析到這裏,事實已經得出:AlarmManager所對應的Binder服務就是AlarmManagerService IAlarmManager service = IAlarmManager.Stub.asInterface(b); return new AlarmManager(service, ctx); }}); registerService(AUDIO_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new AudioManager(ctx); }}); ...省略:下面還有許多服務 }說明:經過上述代碼的分析,相信你們已經很明確Manager是如何和Binder服務一一對應的,而後Manager的各類功能將會交由Binder服務來完成。儘管我只詳細分析了AlarmManager和AlarmManagerService的對應過程,可是其它Manager的對應過程是幾乎徹底同樣的。好了,到了這裏,咱們已經把Manager和Binder服務的對應過程進行了深刻地分析,下面開始咱們的最後一個主題:Alarm機制的源碼分析。
上圖是示意圖,系統中能夠有多個batch,每一個batch中能夠有多個alarm。下面咱們分析一下AlarmManagerService中的代碼。其入口方法爲set,set又調用了setImplLocked,因此咱們直接看setImplLocked。
code:AlarmManagerService#setImplLocked
private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval, PendingIntent operation, boolean isStandalone, boolean doValidate, WorkSource workSource) { /**建立一個alarm,其中各參數的含義以下: * type 鬧鐘類型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等 * when 觸發時間 UTC類型,絕對時間,經過System.currentTimeMillis()獲得 * whenElapsed 相對觸發時間,自開機算起,含休眠,經過SystemClock.elapsedRealtime()獲得 * maxWhen 最大觸發時間 * interval 觸發間隔,針對循環鬧鐘有效 * operation 鬧鐘觸發時的行爲,PendingIntent類型 */ Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource); //根據PendingIntent刪除以前已有的同一個鬧鐘 removeLocked(operation); boolean reschedule; //嘗試將alarm加入到合適的batch中,若是alarm是獨立的或者沒法找到合適的batch去容納此alarm,返回-1 int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen); if (whichBatch < 0) { //沒有合適的batch去容納alarm,則新建一個batch Batch batch = new Batch(a); batch.standalone = isStandalone; //將batch加入mAlarmBatches中,並對mAlarmBatches進行排序:按開始時間升序排列 reschedule = addBatchLocked(mAlarmBatches, batch); } else { //若是找到合適了batch去容納此alarm,則將其加入到batch中 Batch batch = mAlarmBatches.get(whichBatch); //若是當前alarm的加入引發了batch開始時間和結束時間的改變,則reschedule爲true reschedule = batch.add(a); if (reschedule) { //因爲batch的起始時間發生了改變,因此須要從列表中刪除此batch並從新加入、從新對batch列表進行排序 mAlarmBatches.remove(whichBatch); addBatchLocked(mAlarmBatches, batch); } } if (DEBUG_VALIDATE) { if (doValidate && !validateConsistencyLocked()) { Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when + " when(hex)=" + Long.toHexString(when) + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen + " interval=" + interval + " op=" + operation + " standalone=" + isStandalone); rebatchAllAlarmsLocked(false); reschedule = true; } } if (reschedule) { rescheduleKernelAlarmsLocked(); } }
說明:經過上述代碼能夠看出,當咱們建立一個alarm的時候,僅僅是將這個alarm加入到某個batch中,系統中有一個batch列表,專門用於存儲全部的alarm。但是僅僅把alarm加入到batch中還不行,系統還必須提供一個相似於Looper的東西一直去遍歷這個列表,一旦它發現有些alarm的時間已經到達就要把它取出來去執行。事實上,AlarmManagerService中的確有一個相似於Looper的東西去幹這個事情,只不過它是個線程,叫作AlarmThread。下面看它的代碼:
code:AlarmManagerService#AlarmThread
private class AlarmThread extends Thread { public AlarmThread() { super("AlarmManager"); } public void run() { //當前時間觸發的alarm列表 ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); while (true) { //jni方法,顧名思義,阻塞式方法,當有alarm的時候會被喚醒 int result = waitForAlarm(mDescriptor); triggerList.clear(); if ((result & TIME_CHANGED_MASK) != 0) { if (DEBUG_BATCH) { Slog.v(TAG, "Time changed notification from kernel; rebatching"); } remove(mTimeTickSender); //將全部的alarm從新排序 rebatchAllAlarms(); mClockReceiver.scheduleTimeTickEvent(); Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } synchronized (mLock) { final long nowRTC = System.currentTimeMillis(); final long nowELAPSED = SystemClock.elapsedRealtime(); 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++; // number of now-stale entries at the list head } for (int i = 0; i < n; i++) { mRecentWakeups.remove(); } recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC); } } //這個方法會把batch列表中的第一個batch取出來而後加到觸發列表中 //固然,前提是此batch的開始時間不大於當前時間 //同時,若是是循環鬧鐘,則會對下次任務進行再次定時 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); rescheduleKernelAlarmsLocked(); // 遍歷觸發列表,發送PendingIntent for (int i=0; i<triggerList.size(); i++) { Alarm alarm = triggerList.get(i); try { if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); //這裏PendingIntent會被send,結果就是咱們的定時任務被執行了 alarm.operation.send(mContext, 0, mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mResultReceiver, mHandler); // we have an active broadcast so stay awake. if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.operation, alarm.workSource); mWakeLock.acquire(); } final InFlight inflight = new InFlight(AlarmManagerService.this, alarm.operation, alarm.workSource); mInFlight.add(inflight); mBroadcastRefCount++; 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++; //針對能喚醒設備的鬧鐘,這裏會作一些喚醒設備的事情 ActivityManagerNative.noteWakeupAlarm( alarm.operation); } } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { // This IntentSender is no longer valid, but this // is a repeating alarm, so toss the hoser. remove(alarm.operation); } } catch (RuntimeException e) { Slog.w(TAG, "Failure sending alarm.", e); } } } } } }說明:上述代碼中,AlarmThread會一直循環的跑着,一旦有新的alarm觸發,它就會取出一個batch而後逐個發送PendingIntent,具體alarm的觸發是由底層來完成的,我無法再繼續分析下去。還有就是Alarm中有一些細節,我沒有進行很具體的分析,實際上很簡單,你們一看就懂。到此爲止,Alarm機制的主要流程也分析完了。
本文沒有詳細介紹如何使用Alarm,由於很簡單,看一下官方文檔或者網上搜一下,處處都是。關於Alarm,有一點須要強調一下:當手機重啓或者應用被殺死的時候,Alarm會被刪除,所以,若是想經過Alarm來完成長久定時任務是不可靠的,若是非要完成長久定時任務,能夠這樣:將應用的全部Alarm信息存到數據庫中,每次應用啓動的時候都從新註冊Alarm並更新Alarm的觸發時間,經過這種方式就不存在Alarm丟失的狀況了。本文很長,耗時8個小時才完成的,感謝你們閱讀本文,但願本文能給你們帶來一點幫助。