基于 Android7.1.1 源码,分析 AlarmManagerService 的启动流程,这里我们重点关注和分析 java 层的逻辑实现!
java
1 2 3 4 5 6 7 8 9 private void startOtherServices () { ... ... ... traceBeginAndSlog("StartAlarmManagerService" ); mSystemServiceManager.startService(AlarmManagerService.class); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); ... ... ... }
首先会创建 AlarmManagerService 实例对象,然后会调用其 onStart 方法!
1 Constructor java
1 2 3 4 5 public AlarmManagerService (Context context) { super (context); mConstants = new Constants(mHandler); }
AlarmManagerService 的构造器很简单,只是创建了一个 Constants 实例对象!
1.1 new Constants Constants 用来保存 alarm manger 需要的一些常量数据,其内部有一些和属性值!
该类中所有的时间单位都是毫秒,这些常量的值和系统全局设置 Settings.Global 中的值保持同步,任何访问该类或该类中的字段都要持有 AlarmManagerService.mLock 锁!
首先,是一些 Settings.Global 中的 key 值,用于将数据保存到 Settings 中!
java
1 2 3 4 5 6 7 private static final String KEY_MIN_FUTURITY = "min_futurity" ;private static final String KEY_MIN_INTERVAL = "min_interval" ;private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time" ;private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time" ;private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION = "allow_while_idle_whitelist_duration" ; private static final String KEY_LISTENER_TIMEOUT = "listener_timeout" ;
接着是一些 default 值,用于初始化成员变量!
java
1 2 3 4 5 6 7 private static final long DEFAULT_MIN_FUTURITY = 5 * 1000 ; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000 ; private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9 *60 *1000 ;private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10 *1000 ; private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000 ;
最后是一些 alarm manager 会用到的一些成员变量:
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME;public long ALLOW_WHILE_IDLE_WHITELIST_DURATION = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION; public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(',' );private long mLastAllowWhileIdleWhitelistDuration = -1 ;
接着,去看看 Constants 的构造器!
java
1 2 3 4 5 6 public Constants (Handler handler) { super (handler); updateAllowWhileIdleMinTimeLocked(); updateAllowWhileIdleWhitelistDurationLocked(); }
1.2 Constructor.updateAllowWhileIdleMinTimeLocked 这里调用了两个方法:
java
1 2 3 4 5 public void updateAllowWhileIdleMinTimeLocked () { mAllowWhileIdleMinTime = mPendingIdleUntil != null ? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME; }
如果此时已经进入了 idle 状态,那么触发的最小时间间隔为:ALLOW_WHILE_IDLE_LONG_TIME,否则为 ALLOW_WHILE_IDLE_SHORT_TIME!
1.3 Constructor.updateAllowWhileIdleWhitelistDurationLocked java
1 2 3 4 5 6 7 8 9 public void updateAllowWhileIdleWhitelistDurationLocked () { if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) { mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION; BroadcastOptions opts = BroadcastOptions.makeBasic(); opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION); mIdleOptions = opts.toBundle(); } }
继续来看,该方法用于设置 system 更新 idle whilde list 的时间间隔,目前是 10 × 1000 毫秒!
2 onStart 接着是重点 onStart 方法:
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 @Override public void onStart () { mNativeData = init(); mNextWakeup = mNextNonWakeup = 0 ; setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY)); PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*" ); mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0 , new Intent(Intent.ACTION_TIME_TICK).addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND), 0 , UserHandle.ALL); Intent intent = new Intent(Intent.ACTION_DATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0 , intent, Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL); mClockReceiver = new ClockReceiver(); mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); mInteractiveStateReceiver = new InteractiveStateReceiver(); mUninstallReceiver = new UninstallReceiver(); if (mNativeData != 0 ) { AlarmThread waitThread = new AlarmThread(); waitThread.start(); } else { Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler." ); } try { ActivityManagerNative.getDefault().registerUidObserver(new UidObserver(), ActivityManager.UID_OBSERVER_IDLE); } catch (RemoteException e) { } publishBinderService(Context.ALARM_SERVICE, mService); publishLocalService(LocalService.class, new LocalService()); }
下面我们来具体分析下:
2.1 init -> android_server_AlarmManagerService_init java
1 private native long init () ;
可以看到,这是一个 native 方法,方法的定义在:android/frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp 中!
最终会通过 systemCall 进入 native 层,调用 android_server_AlarmManagerService_init 方法!
我们来看看 init 最终做了什么:
java
1 2 3 4 5 6 7 8 9 10 11 static jlong android_server_AlarmManagerService_init (JNIEnv*, jobject) { jlong ret = init_alarm_driver(); if (ret) { return ret; } return init_timerfd(); }
这里我们不过多关注!
2.2 setTimeZoneImpl 更新时区信息,把当前时区保存到内核中!
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void setTimeZoneImpl (String tz) { if (TextUtils.isEmpty(tz)) { return ; } TimeZone zone = TimeZone.getTimeZone(tz); boolean timeZoneWasChanged = false ; synchronized (this ) { String current = SystemProperties.get(TIMEZONE_PROPERTY); if (current == null || !current.equals(zone.getID())) { if (localLOGV) { Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID()); } timeZoneWasChanged = true ; SystemProperties.set(TIMEZONE_PROPERTY, zone.getID()); } int gmtOffset = zone.getOffset(System.currentTimeMillis()); setKernelTimezone(mNativeData, -(gmtOffset / 60000 )); } TimeZone.setDefault(null ); if (timeZoneWasChanged) { Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time-zone" , zone.getID()); getContext().sendBroadcastAsUser(intent, UserHandle.ALL); } }
这里的 setKernelTimezone 是一个 native 方法,这里我们先不看!
java
1 private native int setKernelTimezone (long nativeData, int minuteswest) ;
更新 kernel 时区的信息的原因是,kernel 在重启后,并不会保存时区信息!
2.3 ClockReceiver 我们来看看 ClockReceiver,是一个动态注册的 BroadcastReceiver,用于接收 Intent.ACTION_TIME_TICK 时间改变和 Intent.ACTION_DATE_CHANGED 日期改变的广播!
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class ClockReceiver extends BroadcastReceiver { public ClockReceiver () { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_DATE_CHANGED); getContext().registerReceiver(this , filter); } @Override public void onReceive (Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { if (DEBUG_BATCH) { Slog.v(TAG, "Received TIME_TICK alarm; rescheduling" ); } scheduleTimeTickEvent(); } else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) { TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY)); int gmtOffset = zone.getOffset(System.currentTimeMillis()); setKernelTimezone(mNativeData, -(gmtOffset / 60000 )); scheduleDateChangedEvent(); } } ... ... ... ... }
可以看到:
当收到 Intent.ACTION_TIME_TICK 后,触发 scheduleTimeTickEvent 方法;
当收到 Intent.ACTION_DATE_CHANGED,触发 scheduleDateChangedEvent 方法:
2.3.1 ClockReceiver.scheduleTimeTickEvent 我们来看下 scheduleTimeTickEvent,该方法每一分钟,就会给所有接收 ACTION_TIME_TICK 广播的接收者发送广播,注意这里也包括自身!
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void scheduleTimeTickEvent () { final long currentTime = System.currentTimeMillis(); final long nextTime = 60000 * ((currentTime / 60000 ) + 1 ); final long tickEventDelay = nextTime - currentTime; final WorkSource workSource = null ; setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0 , 0 , mTimeTickSender, null , null , AlarmManager.FLAG_STANDALONE, workSource, null , Process.myUid(), "android" ); }
可以看出 scheduleTimeTickEvent 方法会设置一个 alarm,距离当前时间的下一秒,这个 alarm 会发送 Intent.ACTION_TIME_TICK 广播!
然后 ClockReceiver 会接收到这个广播,然后继续设置下一秒的,发送 Intent.ACTION_TIME_TICK 广播的 alarm,如此循环下去!
2.3.2 ClockReceiver.scheduleDateChangedEvent 我们来看下 scheduleDateChangedEvent:
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void scheduleDateChangedEvent () { Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 0 ); calendar.set(Calendar.MINUTE, 0 ); calendar.set(Calendar.SECOND, 0 ); calendar.set(Calendar.MILLISECOND, 0 ); calendar.add(Calendar.DAY_OF_MONTH, 1 ); final WorkSource workSource = null ; setImpl(RTC, calendar.getTimeInMillis(), 0 , 0 , mDateChangeSender, null , null , AlarmManager.FLAG_STANDALONE, workSource, null , Process.myUid(), "android" ); }
可以看出 scheduleDateChangedEvent 方法会设置一个 alarm,触发事件是下一天的 0 点整,这个 alarm 会发送 Intent.ACTION_DATE_CHANGED 广播!
然后 ClockReceiver 会接收到这个广播,然后继续设置下一天 0 点整的,发送 Intent.Intent.ACTION_DATE_CHANGED 广播的 alarm,如此循环下去!
我们可以看到这里涉及到了一个方法 setImpl ,这个方法我们后续会分析,这里先简单认为其设置了一个 alarm!
2.4 InteractiveStateReceiver InteractiveStateReceiver 用于监控熄屏亮屏的广播!
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class InteractiveStateReceiver extends BroadcastReceiver { public InteractiveStateReceiver () { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); getContext().registerReceiver(this , filter); } @Override public void onReceive (Context context, Intent intent) { synchronized (mLock) { interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); } } }
监听的 Alarm:
Intent.ACTION_SCREEN_OFF
Intent.ACTION_SCREEN_ON
继续来看:
2.4.1 interactiveStateChangedLocked 这里说下参数 interactive,表示接收到的是否亮屏广播:
java
1 Intent.ACTION_SCREEN_ON.equals(intent.getAction())
成员变量 mInteractive 用来保存上一次的熄屏亮屏状态!
接下来,我们来看看 interactiveStateChangedLocked 方法:
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void interactiveStateChangedLocked (boolean interactive) { if (mInteractive != interactive) { mInteractive = interactive; final long nowELAPSED = SystemClock.elapsedRealtime(); if (interactive) { if (mPendingNonWakeupAlarms.size() > 0 ) { final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; mTotalDelayTime += thisDelayTime; if (mMaxDelayTime < thisDelayTime) { mMaxDelayTime = thisDelayTime; } deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED); mPendingNonWakeupAlarms.clear(); } if (mNonInteractiveStartTime > 0 ) { long dur = nowELAPSED - mNonInteractiveStartTime; if (dur > mNonInteractiveTime) { mNonInteractiveTime = dur; } } } else { mNonInteractiveStartTime = nowELAPSED; } } }
3 onBootPhase 在启动的最后阶段,system ready 的时候,会调用 AlarmManagerService 的 onBootPhase 方法!
java
1 2 3 4 5 6 7 8 9 10 11 12 @Override public void onBootPhase (int phase) { if (phase == PHASE_SYSTEM_SERVICES_READY) { mConstants.start(getContext().getContentResolver()); mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mLocalDeviceIdleController = LocalServices.getService(DeviceIdleController.LocalService.class); } }
我们来去看看 Constants.start 方法:
3.1 Constants.start java
1 2 3 4 5 6 7 8 9 public void start (ContentResolver resolver) { mResolver = resolver; mResolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.ALARM_MANAGER_CONSTANTS), false , this ); updateConstants(); }
当 Settings.Global.ALARM_MANAGER_CONSTANTS 的数据发生变化后,会触发 Constants 的回调:
java
1 2 3 4 5 @Override public void onChange (boolean selfChange, Uri uri) { updateConstants(); }
3.2 Constants.updateConstants 更新 Constants 中的属性值!
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private void updateConstants () { synchronized (mLock) { try { mParser.setString(Settings.Global.getString(mResolver, Settings.Global.ALARM_MANAGER_CONSTANTS)); } catch (IllegalArgumentException e) { Slog.e(TAG, "Bad device idle settings" , e); } MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY); MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL); ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME); ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME); ALLOW_WHILE_IDLE_WHITELIST_DURATION = mParser.getLong( KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION, DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION); LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT, DEFAULT_LISTENER_TIMEOUT); updateAllowWhileIdleMinTimeLocked(); updateAllowWhileIdleWhitelistDurationLocked(); } }
Alarm 是 AlarmManagerService 的一个内部类 Alarm,所有应用在设置 Alarm 的时候,都会在 setImplLocked 函数中将 Alarm 格式化为内部类 Alarm 的格式,定义截选如下:
private static class Alarm {
public int type;
public int count;
public long when;
public long repeatInterval;
public PendingIntent operation;
public int uid;
public int pid;
其中记录了逻辑闹钟的一些关键信息。
type域:记录着逻辑闹钟的闹钟类型,比如RTC_WAKEUP、ELAPSED_REALTIME_WAKEUP等;
count域:是个辅助域,它和repeatInterval域一起工作。当repeatInterval大于0时,这个域可被用于计算下一次重复激发alarm的时间。
when域:记录闹钟的激发时间。这个域和type域相关,详细情况见后文;
repeatInterval域:表示重复激发闹钟的时间间隔,如果闹钟只需激发一次,则此域为0,如果闹钟需要重复激发,此域为以毫秒为单位的时间间隔;
operation域:记录闹钟激发时应该执行的动作,详细情况见后文;
uid域:记录设置闹钟的进程的uid;
pid域:记录设置闹钟的进程的pid。