AlarmManager 直接上试用案例,AlarmManager.INTERVAL_DAY时间后触发相关Service:
Intent i = new Intent(EntitlementService.this, EntitlementService.class); i.setAction(ACTION_ENTITLEMENT_CHECK); i.putExtra("service", service); PendingIntent pi = PendingIntent.getService(EntitlementService.this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + AlarmManager.INTERVAL_DAY, AlarmManager.INTERVAL_DAY, pi); * @param type type of alarm. * @param triggerAtMillis time in milliseconds that the alarm should first * go off, using the appropriate clock (depending on the alarm type). * @param intervalMillis interval in milliseconds between subsequent repeats * of the alarm. * @param operation Action to perform when the alarm goes off; * typically comes from {@link PendingIntent#getBroadcast * IntentSender.getBroadcast()}. public void setRepeating(@AlarmType int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) { setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation, null, null, null, null, null); }我们看setImpl()的实现:
private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMillis, long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener, String listenerTag, Handler targetHandler, WorkSource workSource, AlarmClockInfo alarmClock) { ... try { mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags, operation, recipientWrapper, listenerTag, workSource, alarmClock); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } }其实是调用了mService的set方法,mService是IAlarmManager的对象,看名字就可以知道,这里是一个代理类,具体的实现实在AlarmManagerService里面
private final IBinder mService = new IAlarmManager.Stub() { @Override public void set(String callingPackage, int type, long triggerAtTime, long windowLength, long interval, int flags, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) { ... setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver, listenerTag, flags, workSource, alarmClock, callingUid, callingPackage); }
继续展开setImpl:
void setImpl(int type, long triggerAtTime, long windowLength, long interval, PendingIntent operation, IAlarmListener directReceiver, String listenerTag, int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) { ... setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed, interval, operation, directReceiver, listenerTag, flags, true, workSource, alarmClock, callingUid, callingPackage,needAlarmGrouping()); }setImplLocked这个方法会更新AlarmManagerService中的list,该list保存的是整个系统中所有的alarm。 然后调用rescheduleKernelAlarmsLocked-->setLocked
private void setLocked(int type, long when) { if (mNativeData != 0 && mNativeData != -1) { // The kernel never triggers alarms with negative wakeup times // so we ensure they are positive. long alarmSeconds, alarmNanoseconds; if (when < 0) { alarmSeconds = 0; alarmNanoseconds = 0; } else { alarmSeconds = when / 1000; alarmNanoseconds = (when % 1000) * 1000 * 1000; } set(mNativeData, type, alarmSeconds, alarmNanoseconds); } else { Message msg = Message.obtain(); msg.what = ALARM_EVENT; mHandler.removeMessages(ALARM_EVENT); mHandler.sendMessageAtTime(msg, when); } }我们看驱动支持的情况,也就是走: set(mNativeData, type, alarmSeconds, alarmNanoseconds); protected native void set(long nativeData, int type, long seconds, long nanoseconds); 方法实现在 frameworks\base\services\core\jni\com_android_server_AlarmManagerService.cpp
static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds) { AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData); struct timespec ts; ts.tv_sec = seconds; ts.tv_nsec = nanoseconds; int result = impl->set(type, &ts); if (result < 0) { ALOGE("Unable to set alarm to %lld.%09lld: %s\n", static_cast<long long>(seconds), static_cast<long long>(nanoseconds), strerror(errno)); } }AlarmImpl的set方法的实现在AlarmImplAlarmDriver中,先看init方法:
static jlong android_server_AlarmManagerService_init(JNIEnv*, jobject) { jlong ret = init_alarm_driver(); if (ret) { return ret; } return init_timerfd(); }这里驱动支持,走的是init_alarm_driver:
static jlong init_alarm_driver() { int fd = open("/dev/alarm", O_RDWR); if (fd < 0) { ALOGV("opening alarm driver failed: %s", strerror(errno)); return 0; } AlarmImpl *ret = new AlarmImplAlarmDriver(fd); return reinterpret_cast<jlong>(ret); }可以知道如果驱动支持,会在dev目录下面生产一个alarm的节点,在初始化alarm系统的时候fd就不会<0,所以来看看AlarmImplAlarmDriver的set方法:
int AlarmImplAlarmDriver::set(int type, struct timespec *ts) { return ioctl(fds[0], ANDROID_ALARM_SET(type), ts); }通过ioctl的方式将时间设置给驱动,等到硬件中断返回后,再回调到native层,native再回调到framework。
AlarmManagerService
@Override public void onStart() { //这里的init就是读的驱动节点open("/dev/alarm", O_RDWR); mNativeData = init(); ... if (mNativeData != 0) { AlarmThread waitThread = new AlarmThread(); waitThread.start(); } ... }这里驱动支持的话,起了一个线程:
private class AlarmThread extends Thread { public AlarmThread() { super("AlarmManager"); } public void run() { ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); while (true) { int result = waitForAlarm(mNativeData); ... } } }可以看到这里一直的死循环,等待驱动的返回。
int AlarmImplAlarmDriver::waitForAlarm() { return ioctl(fds[0], ANDROID_ALARM_WAIT); }framework回调
void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) { ... mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle); ... } public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) { ... alarm.operation.send(getContext(), 0, mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mDeliveryTracker, mHandler, null, allowWhileIdle ? mIdleOptions : null); ... }这里的operation是PendingIntent对象,最后回调其实是PendingIntent的send方法
public void send(Context context, int code, @Nullable Intent intent, @Nullable OnFinished onFinished, @Nullable Handler handler, @Nullable String requiredPermission, @Nullable Bundle options) throws CanceledException { try { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) : null; int res = ActivityManager.getService().sendIntentSender( mTarget, mWhitelistToken, code, intent, resolvedType, onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, requiredPermission, options); if (res < 0) { throw new CanceledException(); } } catch (RemoteException e) { throw new CanceledException(e); } }这里的mTarget就是驱动回调的起点IIntentSender mTarget,而sendIntentSender的实现便在AMS中:
public int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { if (target instanceof PendingIntentRecord) { return ((PendingIntentRecord)target).sendWithResult(code, intent, resolvedType, whitelistToken, finishedReceiver, requiredPermission, options); } else { if (intent == null) { // Weird case: someone has given us their own custom IIntentSender, and now // they have someone else trying to send to it but of course this isn't // really a PendingIntent, so there is no base Intent, and the caller isn't // supplying an Intent... but we never want to dispatch a null Intent to // a receiver, so um... let's make something up. Slog.wtf(TAG, "Can't use null intent with direct IIntentSender call"); intent = new Intent(Intent.ACTION_MAIN); } try { target.send(code, intent, resolvedType, whitelistToken, null, requiredPermission, options); } catch (RemoteException e) { } // Platform code can rely on getting a result back when the send is done, but if // this intent sender is from outside of the system we can't rely on it doing that. // So instead we don't give it the result receiver, and instead just directly // report the finish immediately. if (finishedReceiver != null) { try { finishedReceiver.performReceive(intent, 0, null, null, false, false, UserHandle.getCallingUserId()); } catch (RemoteException e) { } } return 0; } }最终回调到frameworks\base\services\core\java\com\android\server\am\PendingIntentRecord.java 中的
int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) { ... switch (key.type) { case ActivityManager.INTENT_SENDER_ACTIVITY: ... break; case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: ... break; case ActivityManager.INTENT_SENDER_BROADCAST: ... break; case ActivityManager.INTENT_SENDER_SERVICE: case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: ... break; ... }最后根据不同的类型调用ams的方法启动Broadcast / Activity / Service
Android WakeLock WakeLock levelAndFlags和使用场景
Level保持CPU保持屏幕常亮保持键盘灯常亮使用场景PARTIAL_WAKE_LOCK是否否长时间运行的后台服务,例如Service等SCREEN_DIM_WAKE_LOCK是低亮度否除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式SCREEN_BRIGHT_WAKE_LOCK是高亮度否除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式FULL_WAKE_LOCK是高亮度是除非必须保持CPU运行直至运算完成,否则请使用FLAG_KEEP_SCREEN_ON方式除了这四个Level之外,PowerMager还提供了两个Flag,可以配合Level使用
FLAG描述ACQUIRE_CAUSES_WAKEUP典型的应用就是在收到一个重要的notifications时,需要马上点亮屏幕。ON_AFTER_RELEASE当wake lock被释放的时候,当前调用wake lock的activity的计数器会被重置,所以屏幕会继续亮一段时间使用方法:
public void acquireWakeLock() { if (mWakeLock == null) { PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "XXX"); if (mWakeLock != null) { mWakeLock.acquire(); } } } public void releaseWakeLock() { if (mWakeLock != null) { mWakeLock.release(); } }WakeLock源码 frameworks\base\core\java\android\os\PowerManager.java
public WakeLock newWakeLock(int levelAndFlags, String tag) { validateWakeLockParameters(levelAndFlags, tag); return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName()); } /** @hide */ public static void validateWakeLockParameters(int levelAndFlags, String tag) { switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) { case PARTIAL_WAKE_LOCK: case SCREEN_DIM_WAKE_LOCK: case SCREEN_BRIGHT_WAKE_LOCK: case FULL_WAKE_LOCK: case PROXIMITY_SCREEN_OFF_WAKE_LOCK: case DOZE_WAKE_LOCK: case DRAW_WAKE_LOCK: break; default: throw new IllegalArgumentException("Must specify a valid wake lock level."); } if (tag == null) { throw new IllegalArgumentException("The tag must not be null."); } }继续看构造函数:
WakeLock(int flags, String tag, String packageName) { mFlags = flags; mTag = tag; mPackageName = packageName; mToken = new Binder(); mTraceName = "WakeLock (" + mTag + ")"; } public void acquire() { synchronized (mToken) { acquireLocked(); } } private void acquireLocked() { mInternalCount++; mExternalCount++; if (!mRefCounted || mInternalCount == 1) { // Do this even if the wake lock is already thought to be held (mHeld == true) // because non-reference counted wake locks are not always properly released. // For example, the keyguard's wake lock might be forcibly released by the // power manager without the keyguard knowing. A subsequent call to acquire // should immediately acquire the wake lock once again despite never having // been explicitly released by the keyguard. mHandler.removeCallbacks(mReleaser); Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0); try { mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, mHistoryTag); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } mHeld = true; } }mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource, mHistoryTag); 实现在 frameworks/base/services/java/com/android/server/power/PowerManagerService.java acquireWakeLock -> acquireWakeLockInternal -> updatePowerStateLocked -> updateSuspendBlockerLocked -> acquire -> nativeAcquireSuspendBlocker 到此调用利用JNI调用native代码 private static native void nativeAcquireSuspendBlocker(String name); 实现在: frameworks\base\services\core\jni\com_android_server_power_PowerManagerService.cpp static void nativeAcquireSuspendBlocker(JNIEnv env, jclass / clazz */, jstring nameStr) { ScopedUtfChars name(env, nameStr); acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str()); } 这个acquire_wake_lock是在/hardware/libhardware_legacy/power/power.c里定义的
int acquire_wake_lock(int lock, const char* id) { initialize_fds(); // ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id); if (g_error) return g_error; int fd; size_t len; ssize_t ret; if (lock != PARTIAL_WAKE_LOCK) { return -EINVAL; } fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK]; ret = write(fd, id, strlen(id)); if (ret < 0) { return -errno; } return ret; }const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock", }; fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];将相关锁写入到文件界面, 剩下的便是驱动的实现了,这里不讨论。