免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Alarm機(jī)制與Binder交互

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

前言

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

什么是Alarm

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

  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í)上是類似的,二者在系統(tǒng)休眠的情況下無法正常工作,定時(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開始,Alarm事件默認(rèn)采用非精準(zhǔn)方式,即定時(shí)任務(wù)可能會(huì)有小范圍的提前或延后,當(dāng)然我們可以強(qiáng)制采用精準(zhǔn)方式,而在此之前,Alarm事件都是精準(zhǔn)方式。

Alarm與Binder的交互

Alarm由AlarmManager來管理,從使用方式來看,AlarmManager很簡單,我們只要得到了AlarmManager的對象,就可以調(diào)用set方法來設(shè)定定時(shí)任務(wù)了,而如何得到AlarmManager對象呢?也很簡單,AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);下面我們?nèi)タ纯碅larmManager的set方法,當(dāng)然AlarmManager還有setRepeating方法,但是二者是類似的。為了更好地理解下面的內(nèi)容,需要你了解AIDL,如果你還不了解,請參看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來完成,也就是說AlarmManager只是一個(gè)空殼  
  25.         //從下面的構(gòu)造方法可以看出,這個(gè)mService是IAlarmManager類型的,而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. }  

說明:我對代碼進(jìn)行了注釋,從注釋可以看出,現(xiàn)在我們需要去找到這個(gè)mService,其實(shí)我已經(jīng)幫大家找到了,它就是AlarmManagerService,看下它的類的聲明:

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. }  

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

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

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

上面只是結(jié)論,為了真正搞清楚各種Manager所對應(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)建。該方法太長,我進(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)該能夠大致看出它們所對應(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對應(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所對應(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. }  

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

到此為止,我們已經(jīng)知道各種Binder服務(wù)的創(chuàng)建過程,下面我們要看一下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. }  

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

ContextImpl:Activity的mBase

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

code:mBase的賦值過程

  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
  2.     ...  
  3.     if (activity != null) {  
  4.         //這里的appContext就是ContextImpl對象  
  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.         //通過Activity的attach方法將ContextImpl對象賦值給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對象  
  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對象  
  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.     //這里很顯然,對mBase進(jìn)行賦值  
  50.     mBase = newBase;  
  51. }  

說明:看了上面的代碼,我們已經(jīng)知道,mBase的確是ContextImpl對象。上面我提到:除了LayoutInflater、WindowManager以及SearchManager,剩下的所有Manager將通過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對象  
  6.         //其中SYSTEM_SERVICE_MAP是一個(gè)HashMap,然后再通過fetcher去取service  
  7.         ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);  
  8.         return fetcher == null ? null : fetcher.getService(this);  
  9.     }  
  10.     ...  
  11. }  

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

code:服務(wù)注冊過程和fetcher

  1. //一個(gè)哈希表,用來根據(jù)服務(wù)名存儲(chǔ)對應(yīng)服務(wù)的ServiceFetcher(可以理解為通過ServiceFetcher可以得到服務(wù))  
  2. private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =  
  3.         new HashMap<String, ServiceFetcher>();  
  4.   
  5. //注冊服務(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)代碼塊,注冊各種服務(wù)  
  13. //也就是說,ContextImpl這個(gè)類被加載的時(shí)候就會(huì)把如下的各種服務(wù)的fetcher加入到哈希表中  
  14. //這樣我們通過getSystemService就可以得到一個(gè)服務(wù)的fetcher,再通過fetcher去得到服務(wù)的對象  
  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ù)的注冊  
  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.                 //通過ServiceManager的getService得到Alarm服務(wù),很顯然,下面的b就是AlarmManagerService對象  
  47.                 IBinder b = ServiceManager.getService(ALARM_SERVICE);  
  48.                 //還記得AlarmManager中的mService嗎?就是這里的service,很顯然它是一個(gè)Binder服務(wù)  
  49.                 //分析到這里,事實(shí)已經(jīng)得出:AlarmManager所對應(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. }  
說明:通過上述代碼的分析,相信大家已經(jīng)很明確Manager是如何和Binder服務(wù)一一對應(yīng)的,然后Manager的各種功能將會(huì)交由Binder服務(wù)來完成。盡管我只詳細(xì)分析了AlarmManager和AlarmManagerService的對應(yīng)過程,但是其它Manager的對應(yīng)過程是幾乎完全一樣的。好了,到了這里,我們已經(jīng)把Manager和Binder服務(wù)的對應(yīng)過程進(jìn)行了深入地分析,下面開始我們的最后一個(gè)主題:Alarm機(jī)制的源碼分析。

Alarm機(jī)制分析

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

 

上圖是示意圖,系統(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 鬧鐘類型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等 
  6.      * when 觸發(fā)時(shí)間 UTC類型,絕對時(shí)間,通過System.currentTimeMillis()得到 
  7.      * whenElapsed 相對觸發(fā)時(shí)間,自開機(jī)算起,含休眠,通過SystemClock.elapsedRealtime()得到 
  8.      * maxWhen 最大觸發(fā)時(shí)間 
  9.      * interval 觸發(fā)間隔,針對循環(huán)鬧鐘有效 
  10.      * operation 鬧鐘觸發(fā)時(shí)的行為,PendingIntent類型 
  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ú)立的或者無法找到合適的batch去容納此alarm,返回-1  
  18.     int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);  
  19.     if (whichBatch < 0) {  
  20.         //沒有合適的batch去容納alarm,則新建一個(gè)batch  
  21.         Batch batch = new Batch(a);  
  22.         batch.standalone = isStandalone;  
  23.         //將batch加入mAlarmBatches中,并對mAlarmBatches進(jìn)行排序:按開始時(shí)間升序排列  
  24.         reschedule = addBatchLocked(mAlarmBatches, batch);  
  25.     } else {  
  26.         //如果找到合適了batch去容納此alarm,則將其加入到batch中  
  27.         Batch batch = mAlarmBatches.get(whichBatch);  
  28.         //如果當(dāng)前alarm的加入引起了batch開始時(shí)間和結(jié)束時(shí)間的改變,則reschedule為true  
  29.         reschedule = batch.add(a);  
  30.         if (reschedule) {  
  31.             //由于batch的起始時(shí)間發(fā)生了改變,所以需要從列表中刪除此batch并重新加入、重新對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. }  

說明:通過上述代碼可以看出,當(dāng)我們創(chuàng)建一個(gè)alarm的時(shí)候,僅僅是將這個(gè)alarm加入到某個(gè)batch中,系統(tǒng)中有一個(gè)batch列表,專門用于存儲(chǔ)所有的alarm??墒莾H僅把a(bǔ)larm加入到batch中還不行,系統(tǒng)還必須提供一個(gè)類似于Looper的東西一直去遍歷這個(gè)列表,一旦它發(fā)現(xiàn)有些alarm的時(shí)間已經(jīng)到達(dá)就要把它取出來去執(zhí)行。事實(shí)上,AlarmManagerService中的確有一個(gè)類似于Looper的東西去干這個(gè)事情,只不過它是個(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取出來然后加到觸發(fā)列表中  
  57.                 //當(dāng)然,前提是此batch的開始時(shí)間不大于當(dāng)前時(shí)間  
  58.                 //同時(shí),如果是循環(huán)鬧鐘,則會(huì)對下次任務(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.                             //針對能喚醒設(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. }  
說明:上述代碼中,AlarmThread會(huì)一直循環(huán)的跑著,一旦有新的alarm觸發(fā),它就會(huì)取出一個(gè)batch然后逐個(gè)發(fā)送PendingIntent,具體alarm的觸發(fā)是由底層來完成的,我沒法再繼續(xù)分析下去。還有就是Alarm中有一些細(xì)節(jié),我沒有進(jìn)行很具體的分析,實(shí)際上很簡單,大家一看就懂。到此為止,Alarm機(jī)制的主要流程也分析完了。

總結(jié)

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

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android中Alarm的機(jī)制
[轉(zhuǎn)]Android主動(dòng)開關(guān)機(jī)實(shí)現(xiàn)
桌面Widget動(dòng)態(tài)刷新(alarm控制)
Android系統(tǒng)休眠對程序的影響以及處理
Service關(guān)閉又自動(dòng)啟(AlarmManager、PendingIntent、BroadcastReceiver、Service)
Broadcast調(diào)用Service做的一個(gè)定時(shí)器 - 醋溜的 - JavaEye技術(shù)網(wǎng)站
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服