日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Alarm機(jī)制與Binder交互

 老匹夫 2016-01-16

轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/singwhatiwanna/article/details/18448997

前言

本次給大家分析的是Android中Alarm的機(jī)制以及它和Binder的交互,所用源碼為最新的Android4.4。因?yàn)锳larm的功能都是通過(guò)Binder來(lái)完成的,所以,介紹Alarm之前必須要先介紹下它是如何調(diào)用Binder來(lái)完成定時(shí)功能的。由于內(nèi)容較多,本文會(huì)比較長(zhǎng),在文章結(jié)構(gòu)安排上是這樣的:首先簡(jiǎn)單介紹如何使用Alarm并給出其工作原理,接著分析Alarm和Timer以及Handler在完成定時(shí)任務(wù)上的差別,然后分析Alarm與Binder的交互,最后分析Alarm機(jī)制的源碼。

什么是Alarm

Alarm是android提供的用于完成鬧鐘式定時(shí)任務(wù)的類(lèi),系統(tǒng)通過(guò)AlarmManager來(lái)管理所有的Alarm,Alarm支持一次性定時(shí)任務(wù)和循環(huán)定時(shí)任務(wù),它的使用方式很簡(jiǎn)單,這里不多做介紹,只給出一個(gè)簡(jiǎn)單的示例:

  1. AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);  
  2. Intent intent = new Intent(getApplicationContext(), TestActivity.class);  
  3. PendingIntent pendIntent = PendingIntent.getActivity(getApplicationContext(),  
  4.         0, intent, PendingIntent.FLAG_UPDATE_CURRENT);  
  5. //5秒后發(fā)送廣播,只發(fā)送一次  
  6. int triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000;  
  7. alarmMgr.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, pendIntent);  

Alarm和Timer以及Handler在定時(shí)任務(wù)上的區(qū)別

相同點(diǎn)

三者都可以完成定時(shí)任務(wù),都支持一次性定時(shí)和循環(huán)定時(shí)(注:Handler可以間接支持循環(huán)定時(shí)任務(wù))

不同點(diǎn)

Handler和Timer在定時(shí)上是類(lèi)似的,二者在系統(tǒng)休眠的情況下無(wú)法正常工作,定時(shí)任務(wù)不會(huì)按時(shí)觸發(fā)。Alarm在系統(tǒng)休眠的情況下可以正常工作,并且還可以決定是否喚醒系統(tǒng),同時(shí)Alarm在自身不啟動(dòng)的情況下仍能正常收到定時(shí)任務(wù)提醒,但是當(dāng)系統(tǒng)重啟或者應(yīng)用被殺死的情況下,Alarm定時(shí)任務(wù)會(huì)被取消。另外,從Android4.4開(kāi)始,Alarm事件默認(rèn)采用非精準(zhǔn)方式,即定時(shí)任務(wù)可能會(huì)有小范圍的提前或延后,當(dāng)然我們可以強(qiáng)制采用精準(zhǔn)方式,而在此之前,Alarm事件都是精準(zhǔn)方式。

Alarm與Binder的交互

Alarm由AlarmManager來(lái)管理,從使用方式來(lái)看,AlarmManager很簡(jiǎn)單,我們只要得到了AlarmManager的對(duì)象,就可以調(diào)用set方法來(lái)設(shè)定定時(shí)任務(wù)了,而如何得到AlarmManager對(duì)象呢?也很簡(jiǎn)單,AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);下面我們?nèi)タ纯碅larmManager的set方法,當(dāng)然AlarmManager還有setRepeating方法,但是二者是類(lèi)似的。為了更好地理解下面的內(nèi)容,需要你了解AIDL,如果你還不了解,請(qǐng)參看android跨進(jìn)程通信(IPC):使用AIDL

code:AlarmManager#set

  1. public void set(int type, long triggerAtMillis, PendingIntent operation) {  
  2.     setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null);  
  3. }  
  4.   
  5. public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis,  
  6.         PendingIntent operation, WorkSource workSource) {  
  7.     setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource);  
  8. }  
  9.   
  10. private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,  
  11.         PendingIntent operation, WorkSource workSource) {  
  12.     if (triggerAtMillis < 0) {  
  13.         /* NOTYET 
  14.         if (mAlwaysExact) { 
  15.             // Fatal error for KLP+ apps to use negative trigger times 
  16.             throw new IllegalArgumentException("Invalid alarm trigger time " 
  17.                     + triggerAtMillis); 
  18.         } 
  19.         */  
  20.         triggerAtMillis = 0;  
  21.     }  
  22.   
  23.     try {  
  24.         //定時(shí)任務(wù)實(shí)際上都有mService來(lái)完成,也就是說(shuō)AlarmManager只是一個(gè)空殼  
  25.         //從下面的構(gòu)造方法可以看出,這個(gè)mService是IAlarmManager類(lèi)型的,而IAlarmManager是一個(gè)接口  
  26.         //如果大家了解AIDL就應(yīng)該知道IAlarmManager應(yīng)該是一個(gè)AIDL接口  
  27.         mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,  
  28.                 workSource);  
  29.     } catch (RemoteException ex) {  
  30.     }  
  31. }  
  32.   
  33. AlarmManager(IAlarmManager service, Context ctx) {  
  34.     mService = service;  
  35.   
  36.     final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;  
  37.     mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);  
  38. }  

說(shuō)明:我對(duì)代碼進(jìn)行了注釋?zhuān)瑥淖⑨尶梢钥闯觯F(xiàn)在我們需要去找到這個(gè)mService,其實(shí)我已經(jīng)幫大家找到了,它就是AlarmManagerService,看下它的類(lèi)的聲明:

class AlarmManagerService extends IAlarmManager.Stub

很顯然,AlarmManagerService的確實(shí)現(xiàn)了IAlarmManager接口,為什么是顯然呢?因?yàn)榘凑誂IDL的規(guī)范,IAlarmManager.Stub是按照如下這種方式聲明的:

  1. public static abstract class Stub extends Binder implements IAlarmManager {  
  2.   
  3.     public static IAlarmManager asInterface(IBinder obj)  
  4.     ...  
  5. }  

可見(jiàn)這個(gè)Stub類(lèi)就是一個(gè)普通的Binder,只不過(guò)它實(shí)現(xiàn)了IAlarmManager接口。它還有一個(gè)靜態(tài)方法asInterface,這個(gè)方法很有用,通過(guò)它,我們就可以將IBinder對(duì)象轉(zhuǎn)換成IAlarmManager的實(shí)例,進(jìn)而通過(guò)實(shí)例來(lái)調(diào)用其方法。什么是Binder?這個(gè)還真不好說(shuō),但是我們要知道Binder在Android系統(tǒng)中有大量的應(yīng)用,大部分Manager都通過(guò)Binder來(lái)實(shí)現(xiàn)(包括AlarmManager),而Service和AIDL也是通過(guò)Binder來(lái)實(shí)現(xiàn)調(diào)用的。至于Binder和IBinder的關(guān)系,很簡(jiǎn)單,就是Binder實(shí)現(xiàn)了IBinder接口。由于AlarmManagerService繼承了IAlarmManager.Stub,所以AlarmManagerService也相當(dāng)于實(shí)現(xiàn)了IAlarmManager接口,所以很顯然,AlarmManagerService就是AlarmManager中用于和其交互的mService。不過(guò),還沒(méi)有完,因?yàn)樯厦娴慕Y(jié)論不是我瞎猜的,是有代碼層面的依據(jù)的,下面我將帶領(lǐng)大家一起去探索尋找mService的過(guò)程,通過(guò)這個(gè)過(guò)程,我們會(huì)對(duì)Binder機(jī)制有更加深刻的認(rèn)識(shí)。

各種Manager和Binder服務(wù)的對(duì)應(yīng)關(guān)系

首先Dalvik虛擬機(jī)會(huì)在SystemServer中創(chuàng)建一個(gè)叫做ServerThread的線程并調(diào)用它的initAndLoop方法,在initAndLoop方法中會(huì)創(chuàng)建主線程Looper和初始化各種Manager所對(duì)應(yīng)的Binder服務(wù),我們所常見(jiàn)的Binder服務(wù)如WindowManagerService、AlarmManagerService、PowerManagerService等均在這里創(chuàng)建并加入到ServiceManager中進(jìn)行統(tǒng)一管理。而我們通過(guò)getSystemService方式來(lái)得到各種Manager的工作主要是在ContextImpl中完成的,不過(guò)LayoutInflater、WindowManager以及SearchManager除外。通過(guò)ContextImpl我們可以知道各種Manager和Binder服務(wù)的一一對(duì)應(yīng)關(guān)系,比如AlarmManager對(duì)應(yīng)AlarmManagerService、WindowManager對(duì)應(yīng)WindowManagerService。

上面只是結(jié)論,為了真正搞清楚各種Manager所對(duì)應(yīng)的Binder服務(wù),下面將要看一系列代碼,首先看SystemServer的代碼:

code:SystemServer

  1. public class SystemServer {  
  2.     private static final String TAG = "SystemServer";  
  3.   
  4.     public static final int FACTORY_TEST_OFF = 0;  
  5.     public static final int FACTORY_TEST_LOW_LEVEL = 1;  
  6.     public static final int FACTORY_TEST_HIGH_LEVEL = 2;  
  7.   
  8.     static Timer timer;  
  9.     static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr  
  10.   
  11.     // The earliest supported time.  We pick one day into 1970, to  
  12.     // give any timezone code room without going into negative time.  
  13.     private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;  
  14.   
  15.     /** 
  16.      * Called to initialize native system services. 
  17.      * 初始化本地系統(tǒng)服務(wù),jni方法 
  18.      */  
  19.     private static native void nativeInit();  
  20.   
  21.     //main方法,由底層調(diào)用  
  22.     public static void main(String[] args) {  
  23.         if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {  
  24.             // If a device's clock is before 1970 (before 0), a lot of  
  25.             // APIs crash dealing with negative numbers, notably  
  26.             // java.io.File#setLastModified, so instead we fake it and  
  27.             // hope that time from cell towers or NTP fixes it  
  28.             // shortly.  
  29.             Slog.w(TAG, "System clock is before 1970; setting to 1970.");  
  30.             SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);  
  31.         }  
  32.   
  33.         if (SamplingProfilerIntegration.isEnabled()) {  
  34.             SamplingProfilerIntegration.start();  
  35.             timer = new Timer();  
  36.             timer.schedule(new TimerTask() {  
  37.                 @Override  
  38.                 public void run() {  
  39.                     SamplingProfilerIntegration.writeSnapshot("system_server", null);  
  40.                 }  
  41.             }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);  
  42.         }  
  43.   
  44.         // Mmmmmm... more memory!  
  45.         dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();  
  46.   
  47.         // The system server has to run all of the time, so it needs to be  
  48.         // as efficient as possible with its memory usage.  
  49.         VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);  
  50.   
  51.         Environment.setUserRequired(true);  
  52.   
  53.         System.loadLibrary("android_servers");  
  54.   
  55.         Slog.i(TAG, "Entered the Android system server!");  
  56.   
  57.         // 初始化本地服務(wù).  
  58.         nativeInit();  
  59.   
  60.         //這里是關(guān)鍵,ServerThread被創(chuàng)建,同時(shí)其initAndLoop被調(diào)用  
  61.         ServerThread thr = new ServerThread();  
  62.         thr.initAndLoop();  
  63.     }  
  64. }  

接著看ServerThread的initAndLoop方法,該方法中,主線程Looper會(huì)被創(chuàng)建,各種Binder服務(wù)會(huì)被創(chuàng)建。該方法太長(zhǎng),我進(jìn)行了截?cái)?,只展出我們所關(guān)心的代碼。

code:ServerThread#initAndLoop

  1. public void initAndLoop() {  
  2.     EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,  
  3.         SystemClock.uptimeMillis());  
  4.     //主線程Looper被創(chuàng)建  
  5.     Looper.prepareMainLooper();  
  6.   
  7.     android.os.Process.setThreadPriority(  
  8.             android.os.Process.THREAD_PRIORITY_FOREGROUND);  
  9.   
  10.     BinderInternal.disableBackgroundScheduling(true);  
  11.     android.os.Process.setCanSelfBackground(false);  
  12.     ...此處省略  
  13.     //下面是各種Binder服務(wù),從名字我們應(yīng)該能夠大致看出它們所對(duì)應(yīng)的Manager  
  14.     Installer installer = null;  
  15.     AccountManagerService accountManager = null;  
  16.     ContentService contentService = null;  
  17.     LightsService lights = null;  
  18.     PowerManagerService power = null;  
  19.     DisplayManagerService display = null;  
  20.     BatteryService battery = null;  
  21.     VibratorService vibrator = null;  
  22.     AlarmManagerService alarm = null;  
  23.     MountService mountService = null;  
  24.     NetworkManagementService networkManagement = null;  
  25.     NetworkStatsService networkStats = null;  
  26.     NetworkPolicyManagerService networkPolicy = null;  
  27.     ConnectivityService connectivity = null;  
  28.     WifiP2pService wifiP2p = null;  
  29.     WifiService wifi = null;  
  30.     NsdService serviceDiscovery= null;  
  31.     IPackageManager pm = null;  
  32.     Context context = null;  
  33.     WindowManagerService wm = null;  
  34.     BluetoothManagerService bluetooth = null;  
  35.     DockObserver dock = null;  
  36.     UsbService usb = null;  
  37.     SerialService serial = null;  
  38.     TwilightService twilight = null;  
  39.     UiModeManagerService uiMode = null;  
  40.     RecognitionManagerService recognition = null;  
  41.     NetworkTimeUpdateService networkTimeUpdater = null;  
  42.     CommonTimeManagementService commonTimeMgmtService = null;  
  43.     InputManagerService inputManager = null;  
  44.     TelephonyRegistry telephonyRegistry = null;  
  45.     ConsumerIrService consumerIr = null;  
  46.     ...此處省略  
  47.     Slog.i(TAG, "Alarm Manager");  
  48.     //這里AlarmManager對(duì)應(yīng)的Binder服務(wù)被創(chuàng)建  
  49.     alarm = new AlarmManagerService(context);  
  50.     //將AlarmManagerService加入ServiceManager中統(tǒng)一管理  
  51.     ServiceManager.addService(Context.ALARM_SERVICE, alarm);  
  52.   
  53.     Slog.i(TAG, "Init Watchdog");  
  54.     Watchdog.getInstance().init(context, battery, power, alarm,  
  55.             ActivityManagerService.self());  
  56.     Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");  
  57.   
  58.     Slog.i(TAG, "Input Manager");  
  59.     inputManager = new InputManagerService(context, wmHandler);  
  60.   
  61.     Slog.i(TAG, "Window Manager");  
  62.     //這里WindowManager所對(duì)應(yīng)的Binder服務(wù)被創(chuàng)建  
  63.     wm = WindowManagerService.main(context, power, display, inputManager,  
  64.             wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,  
  65.             !firstBoot, onlyCore);  
  66.     //將WindowManagerService加入ServiceManager中統(tǒng)一管理  
  67.     ServiceManager.addService(Context.WINDOW_SERVICE, wm);  
  68.     ServiceManager.addService(Context.INPUT_SERVICE, inputManager);  
  69.   
  70.     ActivityManagerService.self().setWindowManager(wm);  
  71.     ...此處省略  
  72. }  

說(shuō)明:針對(duì)上述代碼,我要說(shuō)明一下,首先其創(chuàng)建的各種Binder服務(wù)其實(shí)并不是真正的服務(wù),說(shuō)它們是Binder比較恰當(dāng),因?yàn)樗鼈兊拇_繼承自Binder而不是Service;另一點(diǎn)就是ServiceManager其實(shí)也僅僅是個(gè)殼子,真正的工作是通過(guò)其Binder服務(wù)ServiceManagerNative來(lái)完成的,ServiceManager提供的工廠方法addService和getService均在ServiceManagerNative中通過(guò)代理來(lái)實(shí)現(xiàn)。

到此為止,我們已經(jīng)知道各種Binder服務(wù)的創(chuàng)建過(guò)程,下面我們要看一下Manager是如何和其Binder服務(wù)關(guān)聯(lián)上的,再回到getSystemService方法。首先我們要知道Activity的繼承關(guān)系,如下圖所示:


 再看如下代碼,觀察下它們中的getSystemService方法是如何實(shí)現(xiàn)的

code:各種getSystemService方法

  1. //#Context  
  2. public abstract Object getSystemService(String name);  
  3.   
  4. //#ContextWrapper  
  5. @Override  
  6. public Object getSystemService(String name) {  
  7.     return mBase.getSystemService(name);  
  8. }  
  9.   
  10. //#ContextThemeWrapper    
  11. @Override   
  12. public Object getSystemService(String name) {  
  13.     if (LAYOUT_INFLATER_SERVICE.equals(name)) {  
  14.         if (mInflater == null) {  
  15.             mInflater = LayoutInflater.from(mBase).cloneInContext(this);  
  16.         }  
  17.         return mInflater;  
  18.     }  
  19.     return mBase.getSystemService(name);  
  20. }  
  21.   
  22. //#Activity  
  23. @Override  
  24. public Object getSystemService(String name) {  
  25.     if (getBaseContext() == null) {  
  26.         throw new IllegalStateException(  
  27.                 "System services not available to Activities before onCreate()");  
  28.     }  
  29.   
  30.     if (WINDOW_SERVICE.equals(name)) {  
  31.         return mWindowManager;  
  32.     } else if (SEARCH_SERVICE.equals(name)) {  
  33.         ensureSearchManager();  
  34.         return mSearchManager;  
  35.     }  
  36.     return super.getSystemService(name);  
  37. }  

說(shuō)明:通過(guò)上述代碼可以看出LayoutInflater、WindowManager以及SearchManager的處理比較特殊,直接在方法中返回對(duì)象,剩下的所有Manager將通過(guò)mBase.getSystemService(name)返回,現(xiàn)在問(wèn)題轉(zhuǎn)移到mBase上面,mBase是什么呢?我已經(jīng)查清楚了,Activity的mBase就是ContextImpl對(duì)象,何以見(jiàn)得?請(qǐng)看下面分析

ContextImpl:Activity的mBase

不知道大家對(duì)我寫(xiě)的另外一篇源碼分析是否有印象:Android源碼分析-Activity的啟動(dòng)過(guò)程,在這篇文章中我指出:Activity的最終啟動(dòng)過(guò)程由ActivityThread中的performLaunchActivity方法來(lái)完成,在performLaunchActivity中,Activity的mBase將被賦值為ContextImpl對(duì)象,下面通過(guò)代碼來(lái)說(shuō)明:

code:mBase的賦值過(guò)程

  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
  2.     ...  
  3.     if (activity != null) {  
  4.         //這里的appContext就是ContextImpl對(duì)象  
  5.         Context appContext = createBaseContextForActivity(r, activity);  
  6.           
  7.         CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
  8.         Configuration config = new Configuration(mCompatConfiguration);  
  9.         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "  
  10.                 + r.activityInfo.name + " with config " + config);  
  11.         //通過(guò)Activity的attach方法將ContextImpl對(duì)象賦值給mBase  
  12.         activity.attach(appContext, this, getInstrumentation(), r.token,  
  13.                 r.ident, app, r.intent, r.activityInfo, title, r.parent,  
  14.                 r.embeddedID, r.lastNonConfigurationInstances, config);  
  15.         ...  
  16.     }  
  17.     ...  
  18. }  
  19.   
  20. private Context createBaseContextForActivity(ActivityClientRecord r,  
  21.         final Activity activity) {  
  22.     //很顯然,此方法返回的就是ContextImpl對(duì)象  
  23.     ContextImpl appContext = new ContextImpl();  
  24.     appContext.init(r.packageInfo, r.token, this);  
  25.     appContext.setOuterContext(activity);  
  26.     Context baseContext = appContext;  
  27.     ...  
  28.     return baseContext;  
  29. }  
  30.   
  31. final void attach(Context context, ActivityThread aThread,  
  32.         Instrumentation instr, IBinder token, int ident,  
  33.         Application application, Intent intent, ActivityInfo info,  
  34.         CharSequence title, Activity parent, String id,  
  35.         NonConfigurationInstances lastNonConfigurationInstances,  
  36.         Configuration config) {  
  37.     //將context賦值給mBase,這里的context就是performLaunchActivity中的appContext,即ContextImpl對(duì)象  
  38.     attachBaseContext(context);  
  39.   
  40.     mFragments.attachActivity(this, mContainer, null);  
  41.       
  42.     mWindow = PolicyManager.makeNewWindow(this);  
  43.     mWindow.setCallback(this);  
  44.     ...  
  45. }  
  46.   
  47. @Override protected void attachBaseContext(Context newBase) {  
  48.     super.attachBaseContext(newBase);  
  49.     //這里很顯然,對(duì)mBase進(jìn)行賦值  
  50.     mBase = newBase;  
  51. }  

說(shuō)明:看了上面的代碼,我們已經(jīng)知道,mBase的確是ContextImpl對(duì)象。上面我提到:除了LayoutInflater、WindowManager以及SearchManager,剩下的所有Manager將通過(guò)mBase.getSystemService(name)返回,那么現(xiàn)在,我們?nèi)タ聪翪ontextImpl中的getSystemService方法。

code:ContextImpl#getSystemService

  1. class ContextImpl extends Context {  
  2.     ...  
  3.     @Override  
  4.     public Object getSystemService(String name) {  
  5.         //首先從SYSTEM_SERVICE_MAP根據(jù)服務(wù)名得到一個(gè)fetcher對(duì)象  
  6.         //其中SYSTEM_SERVICE_MAP是一個(gè)HashMap,然后再通過(guò)fetcher去取service  
  7.         ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);  
  8.         return fetcher == null ? null : fetcher.getService(this);  
  9.     }  
  10.     ...  
  11. }  

說(shuō)明:看了ContextImpl的getSystemService方法,發(fā)現(xiàn)失望了,還沒(méi)有找到真正的實(shí)現(xiàn),看來(lái)還要去看這個(gè)fetcher是怎么回事,下面請(qǐng)看代碼:

code:服務(wù)注冊(cè)過(guò)程和fetcher

  1. //一個(gè)哈希表,用來(lái)根據(jù)服務(wù)名存儲(chǔ)對(duì)應(yīng)服務(wù)的ServiceFetcher(可以理解為通過(guò)ServiceFetcher可以得到服務(wù))  
  2. private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =  
  3.         new HashMap<String, ServiceFetcher>();  
  4.   
  5. //注冊(cè)服務(wù),將服務(wù)的fetcher存到哈希表中  
  6. private static void registerService(String serviceName, ServiceFetcher fetcher) {  
  7.     if (!(fetcher instanceof StaticServiceFetcher)) {  
  8.         fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;  
  9.     }  
  10.     SYSTEM_SERVICE_MAP.put(serviceName, fetcher);  
  11. }  
  12. //靜態(tài)代碼塊,注冊(cè)各種服務(wù)  
  13. //也就是說(shuō),ContextImpl這個(gè)類(lèi)被加載的時(shí)候就會(huì)把如下的各種服務(wù)的fetcher加入到哈希表中  
  14. //這樣我們通過(guò)getSystemService就可以得到一個(gè)服務(wù)的fetcher,再通過(guò)fetcher去得到服務(wù)的對(duì)象  
  15. static {  
  16.     registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {  
  17.             public Object getService(ContextImpl ctx) {  
  18.                 return AccessibilityManager.getInstance(ctx);  
  19.             }});  
  20.   
  21.     registerService(CAPTIONING_SERVICE, new ServiceFetcher() {  
  22.             public Object getService(ContextImpl ctx) {  
  23.                 return new CaptioningManager(ctx);  
  24.             }});  
  25.   
  26.     registerService(ACCOUNT_SERVICE, new ServiceFetcher() {  
  27.             public Object createService(ContextImpl ctx) {  
  28.                 IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);  
  29.                 IAccountManager service = IAccountManager.Stub.asInterface(b);  
  30.                 return new AccountManager(ctx, service);  
  31.             }});  
  32.   
  33.     registerService(ACTIVITY_SERVICE, new ServiceFetcher() {  
  34.             public Object createService(ContextImpl ctx) {  
  35.                 return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());  
  36.             }});  
  37.   
  38.     //這里是Alarm服務(wù)的注冊(cè)  
  39.     registerService(ALARM_SERVICE, new ServiceFetcher() {  
  40.             public Object createService(ContextImpl ctx) {  
  41.                 /**還記得ALARM_SERVICE嗎? 
  42.                  * alarm = new AlarmManagerService(context); 
  43.                  * 將AlarmManagerService加入ServiceManager中統(tǒng)一管理 
  44.                  * ServiceManager.addService(Context.ALARM_SERVICE, alarm); 
  45.                  */  
  46.                 //通過(guò)ServiceManager的getService得到Alarm服務(wù),很顯然,下面的b就是AlarmManagerService對(duì)象  
  47.                 IBinder b = ServiceManager.getService(ALARM_SERVICE);  
  48.                 //還記得AlarmManager中的mService嗎?就是這里的service,很顯然它是一個(gè)Binder服務(wù)  
  49.                 //分析到這里,事實(shí)已經(jīng)得出:AlarmManager所對(duì)應(yīng)的Binder服務(wù)就是AlarmManagerService  
  50.                 IAlarmManager service = IAlarmManager.Stub.asInterface(b);  
  51.                 return new AlarmManager(service, ctx);  
  52.             }});  
  53.   
  54.     registerService(AUDIO_SERVICE, new ServiceFetcher() {  
  55.             public Object createService(ContextImpl ctx) {  
  56.                 return new AudioManager(ctx);  
  57.             }});  
  58.     ...省略:下面還有許多服務(wù)  
  59. }  
說(shuō)明:通過(guò)上述代碼的分析,相信大家已經(jīng)很明確Manager是如何和Binder服務(wù)一一對(duì)應(yīng)的,然后Manager的各種功能將會(huì)交由Binder服務(wù)來(lái)完成。盡管我只詳細(xì)分析了AlarmManager和AlarmManagerService的對(duì)應(yīng)過(guò)程,但是其它Manager的對(duì)應(yīng)過(guò)程是幾乎完全一樣的。好了,到了這里,我們已經(jīng)把Manager和Binder服務(wù)的對(duì)應(yīng)過(guò)程進(jìn)行了深入地分析,下面開(kāi)始我們的最后一個(gè)主題:Alarm機(jī)制的源碼分析。

Alarm機(jī)制分析

通過(guò)上面的一系列分析,我們知道AlarmManager的所有功能都是通過(guò)AlarmManagerService來(lái)完成的,在分析源碼之前,我先來(lái)描述下Alarm的工作原理:從Android4.4開(kāi)始,Alarm默認(rèn)為非精準(zhǔn)模式,除非顯示指定采用精準(zhǔn)模式。在非精準(zhǔn)模式下,Alarm是批量提醒的,每個(gè)alarm根據(jù)其觸發(fā)時(shí)間和最大觸發(fā)時(shí)間的不同會(huì)被加入到不同的batch中,同一個(gè)batch的不同alarm是同時(shí)發(fā)生的,這樣就無(wú)法實(shí)現(xiàn)精準(zhǔn)鬧鐘,官方的解釋是批量處理可以減少設(shè)備被喚醒次數(shù)以及節(jié)約電量,不過(guò)針對(duì)精準(zhǔn)鬧鐘,官方預(yù)留的方法是setExact和setWindow,二者都是通過(guò)將時(shí)間窗口定義為0來(lái)實(shí)現(xiàn)精準(zhǔn)鬧鐘的,因?yàn)闀r(shí)間窗口為0,意味著觸發(fā)時(shí)間和最大觸發(fā)時(shí)間是一樣的,因?yàn)榈湫偷那闆r下:最大觸發(fā)時(shí)間= 觸發(fā)時(shí)間 + 時(shí)間窗口。同時(shí)所有的batch是按開(kāi)始時(shí)間升序排列的,在一個(gè)batch內(nèi)部,不同的鬧鐘也是按觸發(fā)時(shí)間升序排列的,所以鬧鐘的喚醒順序是按照batch的排序依次觸發(fā)的,而同一個(gè)batch中的alarm是同時(shí)觸發(fā)的,可以用下面這個(gè)示意圖來(lái)描述:

 

上圖是示意圖,系統(tǒng)中可以有多個(gè)batch,每個(gè)batch中可以有多個(gè)alarm。下面我們分析一下AlarmManagerService中的代碼。其入口方法為set,set又調(diào)用了setImplLocked,所以我們直接看setImplLocked。

code:AlarmManagerService#setImplLocked

  1. private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval,  
  2.         PendingIntent operation, boolean isStandalone, boolean doValidate,  
  3.         WorkSource workSource) {  
  4.     /**創(chuàng)建一個(gè)alarm,其中各參數(shù)的含義如下: 
  5.      * type 鬧鐘類(lèi)型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等 
  6.      * when 觸發(fā)時(shí)間 UTC類(lèi)型,絕對(duì)時(shí)間,通過(guò)System.currentTimeMillis()得到 
  7.      * whenElapsed 相對(duì)觸發(fā)時(shí)間,自開(kāi)機(jī)算起,含休眠,通過(guò)SystemClock.elapsedRealtime()得到 
  8.      * maxWhen 最大觸發(fā)時(shí)間 
  9.      * interval 觸發(fā)間隔,針對(duì)循環(huán)鬧鐘有效 
  10.      * operation 鬧鐘觸發(fā)時(shí)的行為,PendingIntent類(lèi)型 
  11.      */  
  12.     Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource);  
  13.     //根據(jù)PendingIntent刪除之前已有的同一個(gè)鬧鐘  
  14.     removeLocked(operation);  
  15.   
  16.     boolean reschedule;  
  17.     //嘗試將alarm加入到合適的batch中,如果alarm是獨(dú)立的或者無(wú)法找到合適的batch去容納此alarm,返回-1  
  18.     int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);  
  19.     if (whichBatch < 0) {  
  20.         //沒(méi)有合適的batch去容納alarm,則新建一個(gè)batch  
  21.         Batch batch = new Batch(a);  
  22.         batch.standalone = isStandalone;  
  23.         //將batch加入mAlarmBatches中,并對(duì)mAlarmBatches進(jìn)行排序:按開(kāi)始時(shí)間升序排列  
  24.         reschedule = addBatchLocked(mAlarmBatches, batch);  
  25.     } else {  
  26.         //如果找到合適了batch去容納此alarm,則將其加入到batch中  
  27.         Batch batch = mAlarmBatches.get(whichBatch);  
  28.         //如果當(dāng)前alarm的加入引起了batch開(kāi)始時(shí)間和結(jié)束時(shí)間的改變,則reschedule為true  
  29.         reschedule = batch.add(a);  
  30.         if (reschedule) {  
  31.             //由于batch的起始時(shí)間發(fā)生了改變,所以需要從列表中刪除此batch并重新加入、重新對(duì)batch列表進(jìn)行排序  
  32.             mAlarmBatches.remove(whichBatch);  
  33.             addBatchLocked(mAlarmBatches, batch);  
  34.         }  
  35.     }  
  36.   
  37.     if (DEBUG_VALIDATE) {  
  38.         if (doValidate && !validateConsistencyLocked()) {  
  39.             Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when  
  40.                     + " when(hex)=" + Long.toHexString(when)  
  41.                     + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen  
  42.                     + " interval=" + interval + " op=" + operation  
  43.                     + " standalone=" + isStandalone);  
  44.             rebatchAllAlarmsLocked(false);  
  45.             reschedule = true;  
  46.         }  
  47.     }  
  48.   
  49.     if (reschedule) {  
  50.         rescheduleKernelAlarmsLocked();  
  51.     }  
  52. }  

說(shuō)明:通過(guò)上述代碼可以看出,當(dāng)我們創(chuàng)建一個(gè)alarm的時(shí)候,僅僅是將這個(gè)alarm加入到某個(gè)batch中,系統(tǒng)中有一個(gè)batch列表,專(zhuān)門(mén)用于存儲(chǔ)所有的alarm??墒莾H僅把a(bǔ)larm加入到batch中還不行,系統(tǒng)還必須提供一個(gè)類(lèi)似于Looper的東西一直去遍歷這個(gè)列表,一旦它發(fā)現(xiàn)有些alarm的時(shí)間已經(jīng)到達(dá)就要把它取出來(lái)去執(zhí)行。事實(shí)上,AlarmManagerService中的確有一個(gè)類(lèi)似于Looper的東西去干這個(gè)事情,只不過(guò)它是個(gè)線程,叫做AlarmThread。下面看它的代碼:

code:AlarmManagerService#AlarmThread

  1. private class AlarmThread extends Thread  
  2. {  
  3.     public AlarmThread()  
  4.     {  
  5.         super("AlarmManager");  
  6.     }  
  7.       
  8.     public void run()  
  9.     {  
  10.         //當(dāng)前時(shí)間觸發(fā)的alarm列表  
  11.         ArrayList<Alarm> triggerList = new ArrayList<Alarm>();  
  12.   
  13.         while (true)  
  14.         {  
  15.             //jni方法,顧名思義,阻塞式方法,當(dāng)有alarm的時(shí)候會(huì)被喚醒  
  16.             int result = waitForAlarm(mDescriptor);  
  17.   
  18.             triggerList.clear();  
  19.   
  20.             if ((result & TIME_CHANGED_MASK) != 0) {  
  21.                 if (DEBUG_BATCH) {  
  22.                     Slog.v(TAG, "Time changed notification from kernel; rebatching");  
  23.                 }  
  24.                 remove(mTimeTickSender);  
  25.                 //將所有的alarm重新排序  
  26.                 rebatchAllAlarms();  
  27.                 mClockReceiver.scheduleTimeTickEvent();  
  28.                 Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);  
  29.                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING  
  30.                         | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);  
  31.                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);  
  32.             }  
  33.               
  34.             synchronized (mLock) {  
  35.                 final long nowRTC = System.currentTimeMillis();  
  36.                 final long nowELAPSED = SystemClock.elapsedRealtime();  
  37.                 if (localLOGV) Slog.v(  
  38.                     TAG, "Checking for alarms... rtc=" + nowRTC  
  39.                     + ", elapsed=" + nowELAPSED);  
  40.   
  41.                 if (WAKEUP_STATS) {  
  42.                     if ((result & IS_WAKEUP_MASK) != 0) {  
  43.                         long newEarliest = nowRTC - RECENT_WAKEUP_PERIOD;  
  44.                         int n = 0;  
  45.                         for (WakeupEvent event : mRecentWakeups) {  
  46.                             if (event.when > newEarliest) break;  
  47.                             n++; // number of now-stale entries at the list head  
  48.                         }  
  49.                         for (int i = 0; i < n; i++) {  
  50.                             mRecentWakeups.remove();  
  51.                         }  
  52.   
  53.                         recordWakeupAlarms(mAlarmBatches, nowELAPSED, nowRTC);  
  54.                     }  
  55.                 }  
  56.                 //這個(gè)方法會(huì)把batch列表中的第一個(gè)batch取出來(lái)然后加到觸發(fā)列表中  
  57.                 //當(dāng)然,前提是此batch的開(kāi)始時(shí)間不大于當(dāng)前時(shí)間  
  58.                 //同時(shí),如果是循環(huán)鬧鐘,則會(huì)對(duì)下次任務(wù)進(jìn)行再次定時(shí)  
  59.                 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);  
  60.                 rescheduleKernelAlarmsLocked();  
  61.   
  62.                 // 遍歷觸發(fā)列表,發(fā)送PendingIntent  
  63.                 for (int i=0; i<triggerList.size(); i++) {  
  64.                     Alarm alarm = triggerList.get(i);  
  65.                     try {  
  66.                         if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);  
  67.                         //這里PendingIntent會(huì)被send,結(jié)果就是我們的定時(shí)任務(wù)被執(zhí)行了  
  68.                         alarm.operation.send(mContext, 0,  
  69.                                 mBackgroundIntent.putExtra(  
  70.                                         Intent.EXTRA_ALARM_COUNT, alarm.count),  
  71.                                 mResultReceiver, mHandler);  
  72.                           
  73.                         // we have an active broadcast so stay awake.  
  74.                         if (mBroadcastRefCount == 0) {  
  75.                             setWakelockWorkSource(alarm.operation, alarm.workSource);  
  76.                             mWakeLock.acquire();  
  77.                         }  
  78.                         final InFlight inflight = new InFlight(AlarmManagerService.this,  
  79.                                 alarm.operation, alarm.workSource);  
  80.                         mInFlight.add(inflight);  
  81.                         mBroadcastRefCount++;  
  82.   
  83.                         final BroadcastStats bs = inflight.mBroadcastStats;  
  84.                         bs.count++;  
  85.                         if (bs.nesting == 0) {  
  86.                             bs.nesting = 1;  
  87.                             bs.startTime = nowELAPSED;  
  88.                         } else {  
  89.                             bs.nesting++;  
  90.                         }  
  91.                         final FilterStats fs = inflight.mFilterStats;  
  92.                         fs.count++;  
  93.                         if (fs.nesting == 0) {  
  94.                             fs.nesting = 1;  
  95.                             fs.startTime = nowELAPSED;  
  96.                         } else {  
  97.                             fs.nesting++;  
  98.                         }  
  99.                         if (alarm.type == ELAPSED_REALTIME_WAKEUP  
  100.                                 || alarm.type == RTC_WAKEUP) {  
  101.                             bs.numWakeup++;  
  102.                             fs.numWakeup++;  
  103.                             //針對(duì)能喚醒設(shè)備的鬧鐘,這里會(huì)做一些喚醒設(shè)備的事情  
  104.                             ActivityManagerNative.noteWakeupAlarm(  
  105.                                     alarm.operation);  
  106.                         }  
  107.                     } catch (PendingIntent.CanceledException e) {  
  108.                         if (alarm.repeatInterval > 0) {  
  109.                             // This IntentSender is no longer valid, but this  
  110.                             // is a repeating alarm, so toss the hoser.  
  111.                             remove(alarm.operation);  
  112.                         }  
  113.                     } catch (RuntimeException e) {  
  114.                         Slog.w(TAG, "Failure sending alarm.", e);  
  115.                     }  
  116.                 }  
  117.             }  
  118.         }  
  119.     }  
  120. }  
說(shuō)明:上述代碼中,AlarmThread會(huì)一直循環(huán)的跑著,一旦有新的alarm觸發(fā),它就會(huì)取出一個(gè)batch然后逐個(gè)發(fā)送PendingIntent,具體alarm的觸發(fā)是由底層來(lái)完成的,我沒(méi)法再繼續(xù)分析下去。還有就是Alarm中有一些細(xì)節(jié),我沒(méi)有進(jìn)行很具體的分析,實(shí)際上很簡(jiǎn)單,大家一看就懂。到此為止,Alarm機(jī)制的主要流程也分析完了。

總結(jié)

本文沒(méi)有詳細(xì)介紹如何使用Alarm,因?yàn)楹芎?jiǎn)單,看一下官方文檔或者網(wǎng)上搜一下,到處都是。關(guān)于Alarm,有一點(diǎn)需要強(qiáng)調(diào)一下:當(dāng)手機(jī)重啟或者應(yīng)用被殺死的時(shí)候,Alarm會(huì)被刪除,因此,如果想通過(guò)Alarm來(lái)完成長(zhǎng)久定時(shí)任務(wù)是不可靠的,如果非要完成長(zhǎng)久定時(shí)任務(wù),可以這樣:將應(yīng)用的所有Alarm信息存到數(shù)據(jù)庫(kù)中,每次應(yīng)用啟動(dòng)的時(shí)候都重新注冊(cè)Alarm并更新Alarm的觸發(fā)時(shí)間,通過(guò)這種方式就不存在Alarm丟失的情況了。本文很長(zhǎng),耗時(shí)8個(gè)小時(shí)才完成的,感謝大家閱讀本文,希望本文能給大家?guī)?lái)一點(diǎn)幫助。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多