轉(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ī)制的源碼。 什么是AlarmAlarm是android提供的用于完成鬧鐘式定時(shí)任務(wù)的類(lèi),系統(tǒng)通過(guò)AlarmManager來(lái)管理所有的Alarm,Alarm支持一次性定時(shí)任務(wù)和循環(huán)定時(shí)任務(wù),它的使用方式很簡(jiǎn)單,這里不多做介紹,只給出一個(gè)簡(jiǎn)單的示例: - 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秒后發(fā)送廣播,只發(fā)送一次
- int triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000;
- 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 - 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 {
- //定時(shí)任務(wù)實(shí)際上都有mService來(lái)完成,也就是說(shuō)AlarmManager只是一個(gè)空殼
- //從下面的構(gòu)造方法可以看出,這個(gè)mService是IAlarmManager類(lèi)型的,而IAlarmManager是一個(gè)接口
- //如果大家了解AIDL就應(yīng)該知道IAlarmManager應(yīng)該是一個(gè)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);
- }
說(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是按照如下這種方式聲明的: - public static abstract class Stub extends Binder implements IAlarmManager {
-
- public static IAlarmManager asInterface(IBinder obj)
- ...
- }
可見(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 - 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.
- * 初始化本地系統(tǒng)服務(wù),jni方法
- */
- private static native void nativeInit();
-
- //main方法,由底層調(diào)用
- 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!");
-
- // 初始化本地服務(wù).
- nativeInit();
-
- //這里是關(guān)鍵,ServerThread被創(chuàng)建,同時(shí)其initAndLoop被調(diào)用
- ServerThread thr = new ServerThread();
- thr.initAndLoop();
- }
- }
接著看ServerThread的initAndLoop方法,該方法中,主線程Looper會(huì)被創(chuàng)建,各種Binder服務(wù)會(huì)被創(chuàng)建。該方法太長(zhǎng),我進(jìn)行了截?cái)?,只展出我們所關(guān)心的代碼。 code:ServerThread#initAndLoop - public void initAndLoop() {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
- SystemClock.uptimeMillis());
- //主線程Looper被創(chuàng)建
- Looper.prepareMainLooper();
-
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_FOREGROUND);
-
- BinderInternal.disableBackgroundScheduling(true);
- android.os.Process.setCanSelfBackground(false);
- ...此處省略
- //下面是各種Binder服務(wù),從名字我們應(yīng)該能夠大致看出它們所對(duì)應(yīng)的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對(duì)應(yīng)的Binder服務(wù)被創(chuàng)建
- alarm = new AlarmManagerService(context);
- //將AlarmManagerService加入ServiceManager中統(tǒng)一管理
- 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所對(duì)應(yīng)的Binder服務(wù)被創(chuàng)建
- wm = WindowManagerService.main(context, power, display, inputManager,
- wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
- !firstBoot, onlyCore);
- //將WindowManagerService加入ServiceManager中統(tǒng)一管理
- ServiceManager.addService(Context.WINDOW_SERVICE, wm);
- ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
-
- ActivityManagerService.self().setWindowManager(wm);
- ...此處省略
- }
說(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方法 - //#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);
- }
說(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ò)程 - private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
- ...
- if (activity != null) {
- //這里的appContext就是ContextImpl對(duì)象
- 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);
- //通過(guò)Activity的attach方法將ContextImpl對(duì)象賦值給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對(duì)象
- 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對(duì)象
- attachBaseContext(context);
-
- mFragments.attachActivity(this, mContainer, null);
-
- mWindow = PolicyManager.makeNewWindow(this);
- mWindow.setCallback(this);
- ...
- }
-
- @Override protected void attachBaseContext(Context newBase) {
- super.attachBaseContext(newBase);
- //這里很顯然,對(duì)mBase進(jìn)行賦值
- mBase = newBase;
- }
說(shuō)明:看了上面的代碼,我們已經(jīng)知道,mBase的確是ContextImpl對(duì)象。上面我提到:除了LayoutInflater、WindowManager以及SearchManager,剩下的所有Manager將通過(guò)mBase.getSystemService(name)返回,那么現(xiàn)在,我們?nèi)タ聪翪ontextImpl中的getSystemService方法。 code:ContextImpl#getSystemService - class ContextImpl extends Context {
- ...
- @Override
- public Object getSystemService(String name) {
- //首先從SYSTEM_SERVICE_MAP根據(jù)服務(wù)名得到一個(gè)fetcher對(duì)象
- //其中SYSTEM_SERVICE_MAP是一個(gè)HashMap,然后再通過(guò)fetcher去取service
- ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
- return fetcher == null ? null : fetcher.getService(this);
- }
- ...
- }
說(shuō)明:看了ContextImpl的getSystemService方法,發(fā)現(xiàn)失望了,還沒(méi)有找到真正的實(shí)現(xiàn),看來(lái)還要去看這個(gè)fetcher是怎么回事,下面請(qǐng)看代碼: code:服務(wù)注冊(cè)過(guò)程和fetcher - //一個(gè)哈希表,用來(lái)根據(jù)服務(wù)名存儲(chǔ)對(duì)應(yīng)服務(wù)的ServiceFetcher(可以理解為通過(guò)ServiceFetcher可以得到服務(wù))
- private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
- new HashMap<String, ServiceFetcher>();
-
- //注冊(cè)服務(wù),將服務(wù)的fetcher存到哈希表中
- private static void registerService(String serviceName, ServiceFetcher fetcher) {
- if (!(fetcher instanceof StaticServiceFetcher)) {
- fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
- }
- SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
- }
- //靜態(tài)代碼塊,注冊(cè)各種服務(wù)
- //也就是說(shuō),ContextImpl這個(gè)類(lèi)被加載的時(shí)候就會(huì)把如下的各種服務(wù)的fetcher加入到哈希表中
- //這樣我們通過(guò)getSystemService就可以得到一個(gè)服務(wù)的fetcher,再通過(guò)fetcher去得到服務(wù)的對(duì)象
- 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服務(wù)的注冊(cè)
- registerService(ALARM_SERVICE, new ServiceFetcher() {
- public Object createService(ContextImpl ctx) {
- /**還記得ALARM_SERVICE嗎?
- * alarm = new AlarmManagerService(context);
- * 將AlarmManagerService加入ServiceManager中統(tǒng)一管理
- * ServiceManager.addService(Context.ALARM_SERVICE, alarm);
- */
- //通過(guò)ServiceManager的getService得到Alarm服務(wù),很顯然,下面的b就是AlarmManagerService對(duì)象
- IBinder b = ServiceManager.getService(ALARM_SERVICE);
- //還記得AlarmManager中的mService嗎?就是這里的service,很顯然它是一個(gè)Binder服務(wù)
- //分析到這里,事實(shí)已經(jīng)得出:AlarmManager所對(duì)應(yīng)的Binder服務(wù)就是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);
- }});
- ...省略:下面還有許多服務(wù)
- }
說(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 - private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval,
- PendingIntent operation, boolean isStandalone, boolean doValidate,
- WorkSource workSource) {
- /**創(chuàng)建一個(gè)alarm,其中各參數(shù)的含義如下:
- * type 鬧鐘類(lèi)型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等
- * when 觸發(fā)時(shí)間 UTC類(lèi)型,絕對(duì)時(shí)間,通過(guò)System.currentTimeMillis()得到
- * whenElapsed 相對(duì)觸發(fā)時(shí)間,自開(kāi)機(jī)算起,含休眠,通過(guò)SystemClock.elapsedRealtime()得到
- * maxWhen 最大觸發(fā)時(shí)間
- * interval 觸發(fā)間隔,針對(duì)循環(huán)鬧鐘有效
- * operation 鬧鐘觸發(fā)時(shí)的行為,PendingIntent類(lèi)型
- */
- Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource);
- //根據(jù)PendingIntent刪除之前已有的同一個(gè)鬧鐘
- removeLocked(operation);
-
- boolean reschedule;
- //嘗試將alarm加入到合適的batch中,如果alarm是獨(dú)立的或者無(wú)法找到合適的batch去容納此alarm,返回-1
- int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
- if (whichBatch < 0) {
- //沒(méi)有合適的batch去容納alarm,則新建一個(gè)batch
- Batch batch = new Batch(a);
- batch.standalone = isStandalone;
- //將batch加入mAlarmBatches中,并對(duì)mAlarmBatches進(jìn)行排序:按開(kāi)始時(shí)間升序排列
- reschedule = addBatchLocked(mAlarmBatches, batch);
- } else {
- //如果找到合適了batch去容納此alarm,則將其加入到batch中
- Batch batch = mAlarmBatches.get(whichBatch);
- //如果當(dāng)前alarm的加入引起了batch開(kāi)始時(shí)間和結(jié)束時(shí)間的改變,則reschedule為true
- reschedule = batch.add(a);
- if (reschedule) {
- //由于batch的起始時(shí)間發(fā)生了改變,所以需要從列表中刪除此batch并重新加入、重新對(duì)batch列表進(jìn)行排序
- 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();
- }
- }
說(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 - private class AlarmThread extends Thread
- {
- public AlarmThread()
- {
- super("AlarmManager");
- }
-
- public void run()
- {
- //當(dāng)前時(shí)間觸發(fā)的alarm列表
- ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
-
- while (true)
- {
- //jni方法,顧名思義,阻塞式方法,當(dāng)有alarm的時(shí)候會(huì)被喚醒
- 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);
- }
- }
- //這個(gè)方法會(huì)把batch列表中的第一個(gè)batch取出來(lái)然后加到觸發(fā)列表中
- //當(dāng)然,前提是此batch的開(kāi)始時(shí)間不大于當(dāng)前時(shí)間
- //同時(shí),如果是循環(huán)鬧鐘,則會(huì)對(duì)下次任務(wù)進(jìn)行再次定時(shí)
- triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
- rescheduleKernelAlarmsLocked();
-
- // 遍歷觸發(fā)列表,發(fā)送PendingIntent
- for (int i=0; i<triggerList.size(); i++) {
- Alarm alarm = triggerList.get(i);
- try {
- if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
- //這里PendingIntent會(huì)被send,結(jié)果就是我們的定時(shí)任務(wù)被執(zhí)行了
- 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++;
- //針對(duì)能喚醒設(shè)備的鬧鐘,這里會(huì)做一些喚醒設(shè)備的事情
- 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);
- }
- }
- }
- }
- }
- }
說(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)幫助。
|