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(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(seconds),
static_cast(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(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 triggerList = new ArrayList();
while (true)
{
int result = waitForAlarm(mNativeData);
...
}
}
}
可以看到这里一直的死循环,等待驱动的返回。
int AlarmImplAlarmDriver::waitForAlarm()
{
return ioctl(fds[0], ANDROID_ALARM_WAIT);
}
framework回调
void deliverAlarmsLocked(ArrayList 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];将相关锁写入到文件界面,
剩下的便是驱动的实现了,这里不讨论。