Android中Alarm的机制

本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4。首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任务上的差别,最后分析Alarm机制的源码。什么是AlarmAlarm是android提供的用于完成闹钟式定时任务的类,系统通过AlarmManager来管理所有的Alarm,Ala
摘要由CSDN通过智能技术生成

本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4。首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任务上的差别,最后分析Alarm机制的源码。

什么是Alarm

Alarm是android提供的用于完成闹钟式定时任务的类,系统通过AlarmManager来管理所有的Alarm,Alarm支持一次性定时任务和循环定时任务,它的使用方式很简单,这里不多做介绍,只给出一个简单的示例:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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秒后发送广播,只发送一次  
  6. int triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000;  
  7. alarmMgr.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, pendIntent); 

Alarm和Timer以及Handler在定时任务上的区别

相同点

三者都可以完成定时任务,都支持一次性定时和循环定时(注:Handler可以间接支持循环定时任务)

不同点

Handler和Timer在定时上是类似的,二者在系统休眠的情况下无法正常工作,定时任务不会按时触发。Alarm在系统休眠的情况下可以正常工作,并且还可以决定是否唤醒系统,同时Alarm在自身不启动的情况下仍能正常收到定时任务提醒,但是当系统重启或者应用被杀死的情况下,Alarm定时任务会被取消。另外,从Android4.4开始,Alarm事件默认采用非精准方式,即定时任务可能会有小范围的提前或延后,当然我们可以强制采用精准方式,而在此之前,Alarm事件都是精准方式。

Alarm与Binder的交互

Alarm由AlarmManager来管理,从使用方式来看,AlarmManager很简单,我们只要得到了AlarmManager的对象,就可以调用set方法来设定定时任务了,而如何得到AlarmManager对象呢?也很简单,AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);下面我们去看看AlarmManager的set方法,当然AlarmManager还有setRepeating方法,但是二者是类似的。为了更好地理解下面的内容,需要你了解AIDL,如果你还不了解,请参看android跨进程通信(IPC):使用AIDL

code:AlarmManager#set

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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.         //定时任务实际上都有mService来完成,也就是说AlarmManager只是一个空壳  
  25.         //从下面的构造方法可以看出,这个mService是IAlarmManager类型的,而IAlarmManager是一个接口  
  26.         //如果大家了解AIDL就应该知道IAlarmManager应该是一个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. }  

说明:我对代码进行了注释,从注释可以看出,现在我们需要去找到这个mService,其实我已经帮大家找到了,它就是AlarmManagerService


Alarm机制分析

通过上面的一系列分析,我们知道AlarmManager的所有功能都是通过AlarmManagerService来完成的,在分析源码之前,我先来描述下Alarm的工作原理:从Android4.4开始,Alarm默认为非精准模式,除非显示指定采用精准模式。在非精准模式下,Alarm是批量提醒的,每个alarm根据其触发时间和最大触发时间的不同会被加入到不同的batch中,同一个batch的不同alarm是同时发生的,这样就无法实现精准闹钟,官方的解释是批量处理可以减少设备被唤醒次数以及节约电量,不过针对精准闹钟,官方预留的方法是setExact和setWindow,二者都是通过将时间窗口定义为0来实现精准闹钟的,因为时间窗口为0,意味着触发时间和最大触发时间是一样的,因为典型的情况下:最大触发时间= 触发时间 + 时间窗口。同时所有的batch是按开始时间升序排列的,在一个batch内部,不同的闹钟也是按触发时间升序排列的,所以闹钟的唤醒顺序是按照batch的排序依次触发的,而同一个batch中的alarm是同时触发的,可以用下面这个示意图来描述:

 

上图是示意图,系统中可以有多个batch,每个batch中可以有多个alarm。下面我们分析一下AlarmManagerService中的代码。其入口方法为set,set又调用了setImplLocked,所以我们直接看setImplLocked。

code:AlarmManagerService#setImplLocked

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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.     /**创建一个alarm,其中各参数的含义如下: 
  5.      * type 闹钟类型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等 
  6.      * when 触发时间 UTC类型,绝对时间,通过System.currentTimeMillis()得到 
  7.      * whenElapsed 相对触发时间,自开机算起,含休眠,通过SystemClock.elapsedRealtime()得到 
  8.      * maxWhen 最大触发时间 
  9.      * interval 触发间隔,针对循环闹钟有效 
  10.      * operation 闹钟触发时的行为,PendingIntent类型 
  11.      */  
  12.     Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource);  
  13.     //根据PendingIntent删除之前已有的同一个闹钟  
  14.     removeLocked(operation);  
  15.   
  16.     boolean reschedule;  
  17.     //尝试将alarm加入到合适的batch中,如果alarm是独立的或者无法找到合适的batch去容纳此alarm,返回-1  
  18.     int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);  
  19.     if (whichBatch < 0) {  
  20.         //没有合适的batch去容纳alarm,则新建一个batch  
  21.         Batch batch = new Batch(a);  
  22.         batch.standalone = isStandalone;  
  23.         //将batch加入mAlarmBatches中,并对mAlarmBatches进行排序:按开始时间升序排列  
  24.         reschedule = addBatchLocked(mAlarmBatches, batch);  
  25.     } else {  
  26.         //如果找到合适了batch去容纳此alarm,则将其加入到batch中  
  27.         Batch batch = mAlarmBatches.get(whichBatch);  
  28.         //如果当前alarm的加入引起了batch开始时间和结束时间的改变,则reschedule为true  
  29.         reschedule = batch.add(a);  
  30.         if (reschedule) {  
  31.             //由于batch的起始时间发生了改变,所以需要从列表中删除此batch并重新加入、重新对batch列表进行排序  
  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. }  

说明:通过上述代码可以看出,当我们创建一个alarm的时候,仅仅是将这个alarm加入到某个batch中,系统中有一个batch列表,专门用于存储所有的alarm。可是仅仅把alarm加入到batch中还不行,系统还必须提供一个类似于Looper的东西一直去遍历这个列表,一旦它发现有些alarm的时间已经到达就要把它取出来去执行。事实上,AlarmManagerService中的确有一个类似于Looper的东西去干这个事情,只不过它是个线程,叫做AlarmThread。下面看它的代码:

code:AlarmManagerService#AlarmThread

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private class AlarmThread extends Thread  
  2. {  
  3.     public AlarmThread()  
  4.     {  
  5.         super("AlarmManager");  
  6.     }  
  7.       
  8.     public void run()  
  9.     {  
  10.         //当前时间触发的alarm列表  
  11.         ArrayList<Alarm> triggerList = new ArrayList<Alarm>();  
  12.   
  13.         while (true)  
  14.         {  
  15.             //jni方法,顾名思义,阻塞式方法,当有alarm的时候会被唤醒  
  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.                 //这个方法会把batch列表中的第一个batch取出来然后加到触发列表中  
  57.                 //当然,前提是此batch的开始时间不大于当前时间  
  58.                 //同时,如果是循环闹钟,则会对下次任务进行再次定时  
  59.                 triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);  
  60.                 rescheduleKernelAlarmsLocked();  
  61.   
  62.                 // 遍历触发列表,发送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会被send,结果就是我们的定时任务被执行了  
  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.                             //针对能唤醒设备的闹钟,这里会做一些唤醒设备的事情  
  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会一直循环的跑着,一旦有新的alarm触发,它就会取出一个batch然后逐个发送PendingIntent,具体alarm的触发是由底层来完成的,我没法再继续分析下去。还有就是Alarm中有一些细节,我没有进行很具体的分析,实际上很简单,大家一看就懂。到此为止,Alarm机制的主要流程也分析完了。

总结

本文没有详细介绍如何使用Alarm,因为很简单,看一下官方文档或者网上搜一下,到处都是。关于Alarm,有一点需要强调一下:当手机重启或者应用被杀死的时候,Alarm会被删除,因此,如果想通过Alarm来完成长久定时任务是不可靠的,如果非要完成长久定时任务,可以这样:将应用的所有Alarm信息存到数据库中,每次应用启动的时候都重新注册Alarm并更新Alarm的触发时间,通过这种方式就不存在Alarm丢失的情况了。





AlarmManager实质上是一个全局定时器,是Android中常用的一种系统服务级别的提示服务,在指定时间或周期性启动其他组件(Activity、Service、BroadcastReceiver)。

之前有篇文章专门介绍了AlarmManager定时器的使用方法,获取到服务后,调用该服务的一些设置方法,在设定时间到达后就会启动指定的组件。

AlarmManagerService和JobSchedulerService一样都是系统服务,故它们的启动流程也类似,先看下时序图:

Zygote进程启动后会启动System进程,在System进程启动过程中会启动系统中的关键服务,如AMS、PMS、JobSchedulerService以及这里要分析的AlarmManagerService。

SystemServer启动AlarmManagerService服务调用的是SystemServiceManager类的startService方法:

[java]  view plain   copy
  1. private void startOtherServices() {  
  2.     try {  
  3.         . . .  
  4.         mSystemServiceManager.startService(AlarmManagerService.class);  
  5.         . . .  
  6.     } catch (RuntimeException e) {  
  7.         Slog.e("System""******************************************");  
  8.         Slog.e("System""************ Failure starting core service", e);  
  9.     }  
  10. }  


SystemServiceManager类的startService方法在JobSchedulerService的分析中已经分析过,这里粘贴写代码:

[java]  view plain   copy
  1. private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();  
  2.   
  3. /** 
  4.  * 创建并启动一个继承自SystemService类的系统服务。 
  5.  * 
  6.  * @param 一个继承自SystemService类的服务类  
  7.  * @return 服务类的实例 
  8.  * @throws 如果服务启动失败则抛RuntimeException异常 
  9.  */  
  10. @SuppressWarnings("unchecked")  
  11. public <T extends SystemService> T startService(Class<T> serviceClass) {  
  12.     // 获取服务类的类名  
  13.     final String name = serviceClass.getName();  
  14.     Slog.i(TAG, "Starting " + name);  
  15.   
  16.     // 判断服务类是否是SystemService的子类  
  17.     if (!SystemService.class.isAssignableFrom(serviceClass)) {  
  18.         throw new RuntimeException("Failed to create " + name  
  19.                 + ": service must extend " + SystemService.class.getName());  
  20.     }  
  21.     final T service;  
  22.     try {  
  23.         // 获取服务类包含一个Context参数的构造方法  
  24.         Constructor<T> constructor = serviceClass.getConstructor(Context.class);  
  25.         // 创建这个服务类的实例  
  26.         service = constructor.newInstance(mContext);  
  27.     } catch (InstantiationException ex) {  
  28.         throw new RuntimeException("Failed to create service " + name  
  29.                 + ": service could not be instantiated", ex);  
  30.     } catch (IllegalAccessException ex) {  
  31.         throw new RuntimeException("Failed to create service " + name  
  32.                 + ": service must have a public constructor with a Context argument", ex);  
  33.     } catch (NoSuchMethodException ex) {  
  34.         throw new RuntimeException("Failed to create service " + name  
  35.                 + ": service must have a public constructor with a Context argument", ex);  
  36.     } catch (InvocationTargetException ex) {  
  37.         throw new RuntimeException("Failed to create service " + name  
  38.                 + ": service constructor threw an exception", ex);  
  39.     }  
  40.   
  41.     // 把服务添加到mServices列表中,方便后续使用时取出  
  42.     mServices.add(service);  
  43.   
  44.     try {  
  45.         // 回调服务的onStart方法  
  46.         service.onStart();  
  47.     } catch (RuntimeException ex) {  
  48.         throw new RuntimeException("Failed to start service " + name  
  49.                 + ": onStart threw an exception", ex);  
  50.     }  
  51.     return service;  
  52. }  


在开启AlarmManagerService服务时,会创建服务的实例,看下该服务的创建过程:

[java]  view plain   copy
  1. final AlarmHandler mHandler = new AlarmHandler();  
  2. final Constants mConstants;  
  3.   
  4. public AlarmManagerService(Context context) {  
  5.     super(context);  
  6.     // 初始化Handler和常量Constants类  
  7.     mConstants = new Constants(mHandler);  
  8. }  


初始化Handler的代码后面调用时再分析,这里先看下常量类的实现:

[java]  view plain   copy
  1. /** 
  2.  * 该类中所有的时间单位都是毫秒。 
  3.  * 这些常量保持与系统全局设置一致。 
  4.  * 任何访问该类或该类中的字段都要持有AlarmManagerService.mLock锁 
  5.  */  
  6. private final class Constants extends ContentObserver {  
  7.     // 在设置中保存的键值  
  8.     private static final String KEY_MIN_FUTURITY = "min_futurity";  
  9.     private static final String KEY_MIN_INTERVAL = "min_interval";  
  10.     private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";  
  11.     private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";  
  12.     private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION  
  13.             = "allow_while_idle_whitelist_duration";  
  14.   
  15.     private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;  
  16.     private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;  
  17.     private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;  
  18.     private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;  
  19.     private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;  
  20.   
  21.     // Minimum futurity of a new alarm  
  22.     public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;  
  23.   
  24.     // Minimum alarm recurrence interval  
  25.     public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;  
  26.   
  27.     // 从系统非空闲状态到可以执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔:5秒钟  
  28.     public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;  
  29.   
  30.     // 从系统空闲状态到可以执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔:9分钟  
  31.     public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME;  
  32.   
  33.     // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.  
  34.     public long ALLOW_WHILE_IDLE_WHITELIST_DURATION  
  35.             = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION;  
  36.   
  37.     private ContentResolver mResolver;  
  38.     private final KeyValueListParser mParser = new KeyValueListParser(',');  
  39.     private long mLastAllowWhileIdleWhitelistDuration = -1;  
  40.   
  41.     public Constants(Handler handler) {  
  42.         super(handler);  
  43.         // 更新可以开始执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔  
  44.         updateAllowWhileIdleMinTimeLocked();  
  45.         updateAllowWhileIdleWhitelistDurationLocked();  
  46.     }  
  47.   
  48.     // 系统启动后会调用该方法,注册数据库监听  
  49.     public void start(ContentResolver resolver) {  
  50.         mResolver = resolver;  
  51.         // 监听数据库变化  
  52.         mResolver.registerContentObserver(Settings.Global.getUriFor(  
  53.                 Settings.Global.ALARM_MANAGER_CONSTANTS), falsethis);  
  54.         updateConstants();  
  55.     }  
  56.   
  57.     // 更新可以开始执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔  
  58.     public void updateAllowWhileIdleMinTimeLocked() {  
  59.         mAllowWhileIdleMinTime = mPendingIdleUntil != null  
  60.                 ? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME;  
  61.     }  
  62.   
  63.     public void updateAllowWhileIdleWhitelistDurationLocked() {  
  64.         if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {  
  65.             mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;  
  66.             BroadcastOptions opts = BroadcastOptions.makeBasic();  
  67.             opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);  
  68.             mIdleOptions = opts.toBundle();  
  69.         }  
  70.     }  
  71.   
  72.     @Override  
  73.     public void onChange(boolean selfChange, Uri uri) {  
  74.         // 数据库内容变化时,更新一些本地变量  
  75.         updateConstants();  
  76.     }  
  77.     . . .  
  78. }  


看下AlarmManagerService类的onStart方法:

[java]  view plain   copy
  1. long mNativeData;  
  2. // 下一个包含wakeup的batch的start时间  
  3. private long mNextWakeup;  
  4. // 下一个包含Rtc wakeup的batch的start时间  
  5. private long mNextRtcWakeup;  
  6. // 下一个非wakeup的batch的start时间  
  7. private long mNextNonWakeup;  
  8. static final String TIMEZONE_PROPERTY = "persist.sys.timezone";  
  9. PowerManager.WakeLock mWakeLock;  
  10. // 时间变化发送者  
  11. PendingIntent mTimeTickSender;  
  12. // 日期变化发送者  
  13. PendingIntent mDateChangeSender;  
  14. // 时间变化的广播接收者  
  15. ClockReceiver mClockReceiver;  
  16. // 监听息屏/亮屏的广播接收者  
  17. InteractiveStateReceiver mInteractiveStateReceiver;  
  18. // 监听卸载的广播接收者  
  19. private UninstallReceiver mUninstallReceiver;  
  20.   
  21. @Override  
  22. public void onStart() {  
  23.     // 通过JNI对mNativeData进行初始化操作:
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值